diff --git a/Directory.Packages.props b/Directory.Packages.props index 7fa6bdf0..bd67a4c1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -25,6 +25,7 @@ + diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Analysis/RunAnalysisEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Analysis/RunAnalysisEndpoint.cs index 86eb67f2..47ccff2a 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Analysis/RunAnalysisEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Analysis/RunAnalysisEndpoint.cs @@ -23,7 +23,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithTags("Analysis") .WithSummary("Run analysis") .WithDescription("Starts the execution of an analysis script on the analysis service.") - .WithRequestValidation(); + .WithRequestValidation() + .WithName("Analyses"); } private static async Task> TriggerAnalysis( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/ClearContextEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/ClearContextEndpoint.cs index 287b90e1..8db1b715 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/ClearContextEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/ClearContextEndpoint.cs @@ -17,7 +17,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) app.MapPost("/api/context/clear", ClearContext) .WithTags("Context") .WithSummary("Clear analysis context") - .WithDescription("Clears all data from the current analysis context."); + .WithDescription("Clears all data from the current analysis context.") + .WithName("Clear"); } private static NoContent ClearContext(IClearContextUseCase useCase) diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GenerateClassesEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GenerateClassesEndpoint.cs index 4502af96..2e3759b6 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GenerateClassesEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GenerateClassesEndpoint.cs @@ -22,7 +22,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithSummary("Generate classes for analysis context") .WithDescription( "Generates script classes based on the current data context and returns them as a stream." - ); + ) + .WithName("GenerateClasses"); } private static async Task> GenerateClasses( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextEndpoint.cs index 0757b688..40ea8332 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextEndpoint.cs @@ -18,7 +18,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) app.MapGet("/api/context", GetContext) .WithTags("Context") .WithSummary("Get analysis context") - .WithDescription("Retrieves the current data context from the analysis service."); + .WithDescription("Retrieves the current data context from the analysis service.") + .WithName("Context"); } private static Ok GetContext(IGetContextUseCase useCase) diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextGraphEndpoints.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextGraphEndpoints.cs index 3275d748..463b0ca2 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextGraphEndpoints.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/GetContextGraphEndpoints.cs @@ -19,24 +19,26 @@ public void DefineEndpoints(IEndpointRouteBuilder app) app.MapGet("/api/context/graph-nodes", SearchNodes) .WithTags("Context", "Graph") .WithSummary("Search context nodes") - .WithDescription("Searches for context nodes based on a query string."); + .WithDescription("Searches for context nodes based on a query string.") + .WithName("GraphNodes"); app.MapGet("/api/context/graph-nodes/{nodeId}/neighbors", GetNeighbors) .WithTags("Context", "Graph") .WithSummary("Get node neighbors") .WithDescription( "Retrieves the immediate neighbors and edges for a specific context node." - ); + ) + .WithName("Neighbors"); } private static Ok SearchNodes( IGetContextGraphUseCase useCase, - [FromQuery] string? query, + [FromQuery] string query = "", [FromQuery] int offset = 0, [FromQuery] int limit = 10 ) { - var result = useCase.SearchNodes(query ?? string.Empty, offset, limit); + var result = useCase.SearchNodes(query, offset, limit); return TypedResults.Ok( new WebContextGraphResponse( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LinkContextEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LinkContextEndpoint.cs index b3dc58f2..97fad5b9 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LinkContextEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LinkContextEndpoint.cs @@ -21,7 +21,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithTags("Context") .WithSummary("Link analysis context") .WithDescription("Links the current analysis context using the provided linkers.") - .WithRequestValidation(); + .WithRequestValidation() + .WithName("Link"); } private static async Task LinkContext( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LoadContextEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LoadContextEndpoint.cs index 77c8621e..3a0f370e 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LoadContextEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Context/LoadContextEndpoint.cs @@ -24,7 +24,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithDescription( "Loads data from files into the current analysis context using the provided loaders." ) - .WithRequestValidation(); + .WithRequestValidation() + .WithName("Load"); } private static async Task LoadContext( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebInstalledPluginManifest.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebInstalledPluginManifest.cs index 44c6ad44..51b0046f 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebInstalledPluginManifest.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebInstalledPluginManifest.cs @@ -7,7 +7,7 @@ public record WebInstalledPluginManifest( string Name, string? Description, string? Author, - IEnumerable ExtensionPoints + IEnumerable ExtensionPoints ) { public static WebInstalledPluginManifest Map(PluginManifest pluginManifest) @@ -17,57 +17,69 @@ public static WebInstalledPluginManifest Map(PluginManifest pluginManifest) pluginManifest.Name, pluginManifest.Description, pluginManifest.Author, - pluginManifest.ExtensionPoints.Select(MapExtensionPoint) + pluginManifest + .ExtensionPoints.Select(MapExtensionPoint) + .Where(extensionPoint => extensionPoint is not null) + .Cast() ); } - private static object MapExtensionPoint(PluginExtensionPoint extensionPoint) + private static WebPluginExtensionPoint? MapExtensionPoint(PluginExtensionPoint extensionPoint) { return extensionPoint switch { + HelperFunctionsPluginExtensionPoint helperFunctionsPluginExtensionPoint => + new WebHelperFunctionsPluginExtensionPoint( + helperFunctionsPluginExtensionPoint.Kind, + helperFunctionsPluginExtensionPoint.EntryPoint, + helperFunctionsPluginExtensionPoint.Version + ), + LinkerPluginExtensionPoint linkerPluginExtensionPoint => + new WebLinkerPluginExtensionPoint( + linkerPluginExtensionPoint.Kind, + linkerPluginExtensionPoint.EntryPoint, + linkerPluginExtensionPoint.Version + ), + LoaderPluginExtensionPoint loaderPluginExtensionPoint => + new WebLoaderPluginExtensionPoint( + loaderPluginExtensionPoint.Kind, + loaderPluginExtensionPoint.EntryPoint, + loaderPluginExtensionPoint.Version + ), + + PluginBundleExtensionPoint pluginBundleExtensionPoint => + new WebNestedPluginExtensionPoint( + pluginBundleExtensionPoint.Kind, + pluginBundleExtensionPoint.EntryPoint, + pluginBundleExtensionPoint.Version + ), ScriptGeneratorPluginExtensionPoint scriptGeneratorPluginExtensionPoint => - new WebScriptGeneratorPluginExtensionPoint - { - EntryPoint = scriptGeneratorPluginExtensionPoint.EntryPoint, - Kind = scriptGeneratorPluginExtensionPoint.Kind, - Version = scriptGeneratorPluginExtensionPoint.Version, - Extension = scriptGeneratorPluginExtensionPoint.Extension, - Language = scriptGeneratorPluginExtensionPoint.Language, - }, + new WebScriptGeneratorPluginExtensionPoint( + scriptGeneratorPluginExtensionPoint.Kind, + scriptGeneratorPluginExtensionPoint.EntryPoint, + scriptGeneratorPluginExtensionPoint.Version, + scriptGeneratorPluginExtensionPoint.Language, + scriptGeneratorPluginExtensionPoint.Extension + ), ScriptRunnerPluginExtensionPoint scriptRunnerPluginExtensionPoint => - new WebScriptRunnerPluginExtensionPoint - { - Kind = scriptRunnerPluginExtensionPoint.Kind, - EntryPoint = scriptRunnerPluginExtensionPoint.EntryPoint, - Version = scriptRunnerPluginExtensionPoint.Version, - Language = scriptRunnerPluginExtensionPoint.Language, - Extension = scriptRunnerPluginExtensionPoint.Extension, - }, - UiPluginExtensionPoint uiPluginExtensionPoint => new WebUiPluginExtensionPoint - { - EntryPoint = uiPluginExtensionPoint.EntryPoint, - Kind = uiPluginExtensionPoint.Kind, - Version = uiPluginExtensionPoint.Version, - RemoteName = uiPluginExtensionPoint.RemoteName, - RemoteEntry = uiPluginExtensionPoint.RemoteEntry, - Outlets = uiPluginExtensionPoint.Outlets.Select(o => new WebUiPluginOutlet - { - Type = o.Type, - ExposedModule = (o as RoutingOutlet)?.ExposedModule ?? string.Empty, - Path = (o as RoutingOutlet)?.Path, - Label = (o as RoutingOutlet)?.Label, - Nested = (o as RoutingOutlet)?.Nested, - ComponentName = (o as RoutingOutlet)?.ComponentName, - Icon = (o as SidePanelOutlet)?.Icon, - SupportedFileExtensions = (o as FilePreviewerOutlet)?.SupportedFileExtensions, - }), - }, - _ => new WebPluginExtensionPoint - { - EntryPoint = extensionPoint.EntryPoint, - Kind = extensionPoint.Kind, - Version = extensionPoint.Version, - }, + new WebScriptRunnerPluginExtensionPoint( + scriptRunnerPluginExtensionPoint.Kind, + scriptRunnerPluginExtensionPoint.EntryPoint, + scriptRunnerPluginExtensionPoint.Version, + scriptRunnerPluginExtensionPoint.Language, + scriptRunnerPluginExtensionPoint.Extension + ), + UiPluginExtensionPoint uiPluginExtensionPoint => new WebUiPluginExtensionPoint( + uiPluginExtensionPoint.Kind, + uiPluginExtensionPoint.EntryPoint, + uiPluginExtensionPoint.Version, + uiPluginExtensionPoint.RemoteName, + uiPluginExtensionPoint.RemoteEntry, + uiPluginExtensionPoint.Outlets.Select( + WebInstalledPluginExtensionPointOutletBase.Map + ) + ), + _ => null, }; } } diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebPluginExtensionPoint.cs index fa381c52..f4e94e0a 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebPluginExtensionPoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebPluginExtensionPoint.cs @@ -1,8 +1,73 @@ -namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; - -public class WebPluginExtensionPoint -{ - public string Kind { get; set; } = ""; - public string EntryPoint { get; set; } = ""; - public string Version { get; set; } = ""; -} +using System.ComponentModel; +using System.Text.Json.Serialization; +using ScriptBee.Domain.Model.Plugins.Manifest; + +namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "kind")] +[Description("Base class for plugin extension points")] +[JsonDerivedType(typeof(WebNestedPluginExtensionPoint), typeDiscriminator: PluginKind.Plugin)] +[JsonDerivedType(typeof(WebLoaderPluginExtensionPoint), typeDiscriminator: PluginKind.Loader)] +[JsonDerivedType(typeof(WebLinkerPluginExtensionPoint), typeDiscriminator: PluginKind.Linker)] +[JsonDerivedType( + typeof(WebScriptGeneratorPluginExtensionPoint), + typeDiscriminator: PluginKind.ScriptGenerator +)] +[JsonDerivedType( + typeof(WebScriptRunnerPluginExtensionPoint), + typeDiscriminator: PluginKind.ScriptRunner +)] +[JsonDerivedType( + typeof(WebHelperFunctionsPluginExtensionPoint), + typeDiscriminator: PluginKind.HelperFunctions +)] +[JsonDerivedType(typeof(WebUiPluginExtensionPoint), typeDiscriminator: PluginKind.Ui)] +public abstract record WebPluginExtensionPoint( + [property: JsonIgnore] string Kind, + string EntryPoint, + string Version +); + +[Description("Represents a plugin from a bundle.")] +public record WebNestedPluginExtensionPoint(string Kind, string EntryPoint, string Version) + : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a loader plugin extension point.")] +public record WebLoaderPluginExtensionPoint(string Kind, string EntryPoint, string Version) + : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a linker plugin extension point.")] +public record WebLinkerPluginExtensionPoint(string Kind, string EntryPoint, string Version) + : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a script generator plugin extension point.")] +public record WebScriptGeneratorPluginExtensionPoint( + string Kind, + string EntryPoint, + string Version, + string Language, + string Extension +) : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a script runner plugin extension point.")] +public record WebScriptRunnerPluginExtensionPoint( + string Kind, + string EntryPoint, + string Version, + string Language, + string Extension +) : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a helper functions plugin extension point.")] +public record WebHelperFunctionsPluginExtensionPoint(string Kind, string EntryPoint, string Version) + : WebPluginExtensionPoint(Kind, EntryPoint, Version); + +[Description("Represents a UI plugin extension point.")] +public record WebUiPluginExtensionPoint( + string Kind, + string EntryPoint, + string Version, + string RemoteName, + string RemoteEntry, + IEnumerable Outlets +) : WebPluginExtensionPoint(Kind, EntryPoint, Version); diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptGeneratorPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptGeneratorPluginExtensionPoint.cs deleted file mode 100644 index 2f2ff091..00000000 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptGeneratorPluginExtensionPoint.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; - -public class WebScriptGeneratorPluginExtensionPoint -{ - public string Kind { get; set; } = ""; - public string EntryPoint { get; set; } = ""; - public string Version { get; set; } = ""; - - public string Language { get; set; } = ""; - public string Extension { get; set; } = ""; -} diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptRunnerPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptRunnerPluginExtensionPoint.cs deleted file mode 100644 index 30e4dc0c..00000000 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebScriptRunnerPluginExtensionPoint.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; - -public class WebScriptRunnerPluginExtensionPoint -{ - public string Kind { get; set; } = ""; - public string EntryPoint { get; set; } = ""; - public string Version { get; set; } = ""; - - public string Language { get; set; } = ""; - public string Extension { get; set; } = ""; -} diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPoint.cs deleted file mode 100644 index e54c90a1..00000000 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPoint.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; - -public class WebUiPluginExtensionPoint -{ - public string Kind { get; set; } = ""; - public string EntryPoint { get; set; } = ""; - public string Version { get; set; } = ""; - - public string RemoteName { get; set; } = ""; - public string RemoteEntry { get; set; } = ""; - public IEnumerable Outlets { get; set; } = []; -} - -public class WebUiPluginOutlet -{ - public string Type { get; set; } = ""; - public string ExposedModule { get; set; } = ""; - public string? Path { get; set; } - public string? Label { get; set; } - public bool? Nested { get; set; } - public string? ComponentName { get; set; } - public string? Icon { get; set; } - public List? SupportedFileExtensions { get; set; } -} diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPointOutlet.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPointOutlet.cs new file mode 100644 index 00000000..4ba619bd --- /dev/null +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/Contracts/WebUiPluginExtensionPointOutlet.cs @@ -0,0 +1,89 @@ +using System.ComponentModel; +using System.Text.Json.Serialization; +using ScriptBee.Domain.Model.Plugins.Manifest; + +namespace ScriptBee.Analysis.Web.EndpointDefinitions.Plugins.Contracts; + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +[JsonDerivedType( + typeof(WebInstalledPluginTopNavigationBarOutlet), + typeDiscriminator: OutletTypes.TopNavigationBar +)] +[JsonDerivedType( + typeof(WebInstalledPluginSidePanelOutlet), + typeDiscriminator: OutletTypes.SidePanel +)] +[JsonDerivedType( + typeof(WebInstalledPluginFilePreviewerOutlet), + typeDiscriminator: OutletTypes.FilePreviewer +)] +[Description("Base class for outlets of a plugin extension point.")] +public abstract record WebInstalledPluginExtensionPointOutletBase( + [property: JsonIgnore] string Type +) +{ + public static WebInstalledPluginExtensionPointOutletBase Map( + UiPluginExtensionPointOutlet outlet + ) => + outlet switch + { + TopNavigationBarOutlet topNavigationBarOutlet => + new WebInstalledPluginTopNavigationBarOutlet( + topNavigationBarOutlet.Type, + topNavigationBarOutlet.ExposedModule, + topNavigationBarOutlet.Label, + topNavigationBarOutlet.Path, + topNavigationBarOutlet.Nested, + topNavigationBarOutlet.ComponentName + ), + SidePanelOutlet sidePanelOutlet => new WebInstalledPluginSidePanelOutlet( + sidePanelOutlet.Type, + sidePanelOutlet.ExposedModule, + sidePanelOutlet.Label, + sidePanelOutlet.Path, + sidePanelOutlet.Nested, + sidePanelOutlet.ComponentName, + sidePanelOutlet.Icon + ), + FilePreviewerOutlet filePreviewerOutlet => new WebInstalledPluginFilePreviewerOutlet( + filePreviewerOutlet.Type, + filePreviewerOutlet.ExposedModule, + filePreviewerOutlet.Label, + filePreviewerOutlet.ComponentName, + filePreviewerOutlet.Icon, + filePreviewerOutlet.SupportedFileExtensions + ), + _ => throw new ArgumentOutOfRangeException(nameof(outlet), outlet, null), + }; +} + +[Description("Represents an element from the Top Navigation Bar with route.")] +public record WebInstalledPluginTopNavigationBarOutlet( + string Type, + string ExposedModule, + string Label, + string Path, + bool? Nested, + string? ComponentName +) : WebInstalledPluginExtensionPointOutletBase(Type); + +[Description("Represents an element from the Side Hamburger Panel with route.")] +public record WebInstalledPluginSidePanelOutlet( + string Type, + string ExposedModule, + string Label, + string Path, + bool? Nested, + string? ComponentName, + string Icon +) : WebInstalledPluginExtensionPointOutletBase(Type); + +[Description("Represents a component for file previewer of output results.")] +public record WebInstalledPluginFilePreviewerOutlet( + string Type, + string ExposedModule, + string Label, + string? ComponentName, + string? Icon, + List? SupportedFileExtensions +) : WebInstalledPluginExtensionPointOutletBase(Type); diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/GetInstalledPluginsEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/GetInstalledPluginsEndpoint.cs index aad61eab..c3aad755 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/GetInstalledPluginsEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/GetInstalledPluginsEndpoint.cs @@ -20,7 +20,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithSummary("Get installed plugins") .WithDescription( "Retrieves a list of all plugins currently installed in the analysis service." - ); + ) + .WithName("PluginsGet"); } private static Ok GetInstalledPlugins( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/InstallPluginEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/InstallPluginEndpoint.cs index ed3f7bcb..d44e9139 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/InstallPluginEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/InstallPluginEndpoint.cs @@ -29,7 +29,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) .WithTags("Plugins") .WithSummary("Install a plugin") .WithDescription("Installs a specific plugin version into the analysis service.") - .WithRequestValidation(); + .WithRequestValidation() + .WithName("PluginsPost"); } private static InstallResult InstallPlugin( diff --git a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/UninstallPluginEndpoint.cs b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/UninstallPluginEndpoint.cs index bd77d7be..5a31ab6a 100644 --- a/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/UninstallPluginEndpoint.cs +++ b/ScriptBeeWebApp/src/Analysis/Adapters/Analysis.Web/EndpointDefinitions/Plugins/UninstallPluginEndpoint.cs @@ -19,7 +19,8 @@ public void DefineEndpoints(IEndpointRouteBuilder app) app.MapDelete("/api/plugins/{pluginId}", UninstallPlugin) .WithTags("Plugins") .WithSummary("Uninstall a plugin") - .WithDescription("Uninstalls a specific plugin version from the analysis service."); + .WithDescription("Uninstalls a specific plugin version from the analysis service.") + .WithName("PluginsDelete"); } private static NoContent UninstallPlugin( diff --git a/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/PluginKind.cs b/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/PluginKind.cs index 422b4894..6c3ad535 100644 --- a/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/PluginKind.cs +++ b/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/PluginKind.cs @@ -10,3 +10,10 @@ public static class PluginKind public const string HelperFunctions = "HelperFunctions"; public const string Ui = "UI"; } + +public static class OutletTypes +{ + public const string TopNavigationBar = "top-navigation-bar"; + public const string SidePanel = "side-panel"; + public const string FilePreviewer = "file-previewer"; +} diff --git a/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/UiPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/UiPluginExtensionPoint.cs index 79f2e246..98e2a47d 100644 --- a/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/UiPluginExtensionPoint.cs +++ b/ScriptBeeWebApp/src/Common/Model/Plugins/Manifest/UiPluginExtensionPoint.cs @@ -30,6 +30,25 @@ public class SidePanelOutlet : RoutingOutlet public class FilePreviewerOutlet : UiPluginExtensionPointOutlet { + public FilePreviewerOutlet() { } + + public FilePreviewerOutlet( + string type, + string exposedModule, + string label, + string? componentName, + string? icon, + List? supportedFileExtensions + ) + { + Type = type; + ExposedModule = exposedModule; + Label = label; + ComponentName = componentName; + Icon = icon; + SupportedFileExtensions = supportedFileExtensions; + } + public string ExposedModule { get; set; } = ""; public string Label { get; set; } = ""; public string? ComponentName { get; set; } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IAnalysisApi.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IAnalysisApi.cs deleted file mode 100644 index d96ba64e..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IAnalysisApi.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Refit; -using ScriptBee.Rest.Contracts; - -namespace ScriptBee.Rest.Api; - -public interface IAnalysisApi -{ - [Post("/api/analyses")] - Task TriggerAnalysis( - [Body] RestRunAnalysisCommand request, - CancellationToken cancellationToken - ); -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IContextApi.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IContextApi.cs deleted file mode 100644 index a2db8d55..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IContextApi.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Refit; -using ScriptBee.Rest.Contracts; - -namespace ScriptBee.Rest.Api; - -public interface IContextApi -{ - [Get("/api/context")] - Task Get(CancellationToken cancellationToken); - - [Post("/api/context/clear")] - Task Clear(CancellationToken cancellationToken); - - [Post("/api/context/link")] - Task Link([Body] RestContextLink request, CancellationToken cancellationToken); - - [Post("/api/context/load")] - Task Load([Body] RestContextLoad request, CancellationToken cancellationToken); - - [Post("/api/context/generate-classes")] - Task GenerateClasses( - [Body] RestGenerateClasses request, - CancellationToken cancellationToken - ); - - [Get("/api/context/graph-nodes")] - Task SearchNodes( - [Query] string? query, - [Query] int offset, - [Query] int limit, - CancellationToken cancellationToken - ); - - [Get("/api/context/graph-nodes/{nodeId}/neighbors")] - Task GetNeighbors( - [AliasAs("nodeId")] string nodeId, - CancellationToken cancellationToken - ); -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IPluginsApi.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IPluginsApi.cs deleted file mode 100644 index e1576486..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Api/IPluginsApi.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Refit; -using ScriptBee.Rest.Contracts; - -namespace ScriptBee.Rest.Api; - -public interface IPluginsApi -{ - [Get("/api/plugins")] - Task GetInstalledPlugins(CancellationToken cancellationToken); - - [Post("/api/plugins")] - Task InstallPlugin([Body] RestInstallPlugin request, CancellationToken cancellationToken); - - [Delete("/api/plugins/{pluginId}")] - Task UninstallPlugin( - [AliasAs("pluginId")] string pluginId, - [Query] string version, - CancellationToken cancellationToken - ); -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/ClearInstanceContextAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/ClearInstanceContextAdapter.cs index 40a2bafd..3b6243d5 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/ClearInstanceContextAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/ClearInstanceContextAdapter.cs @@ -1,7 +1,7 @@ using Refit; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; +using ScriptBee.Rest.Api.Generated; namespace ScriptBee.Rest; @@ -16,7 +16,7 @@ public async Task Clear( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var contextApi = RestService.For(client); await contextApi.Clear(cancellationToken); } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphEdge.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphEdge.cs deleted file mode 100644 index 3e76f4ee..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphEdge.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ScriptBee.Domain.Model.Context; - -namespace ScriptBee.Rest.Contracts; - -public record RestContextGraphEdge(string Source, string Target, string Label) -{ - public ContextGraphEdge Map() => new(Source, Target, Label); -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphNode.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphNode.cs deleted file mode 100644 index a92d69a8..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphNode.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ScriptBee.Domain.Model.Context; - -namespace ScriptBee.Rest.Contracts; - -public record RestContextGraphNode( - string Id, - string Label, - string Type, - string? Loader, - Dictionary Properties -) -{ - public ContextGraphNode Map() => new(Id, Label, Type, Loader, Properties); -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphResponse.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphResponse.cs deleted file mode 100644 index 23a6a198..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextGraphResponse.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public record RestContextGraphResponse( - IEnumerable Nodes, - IEnumerable Edges -); diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLink.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLink.cs deleted file mode 100644 index b9f56890..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLink.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public class RestContextLink -{ - public required IEnumerable LinkerIds { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLoad.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLoad.cs deleted file mode 100644 index 81872a35..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextLoad.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public class RestContextLoad -{ - public required IDictionary> FilesToLoad { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextSlice.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextSlice.cs deleted file mode 100644 index 0755777d..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestContextSlice.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ScriptBee.Domain.Model.Context; - -namespace ScriptBee.Rest.Contracts; - -public class RestContextSlice -{ - public required string Model { get; set; } - - public required IEnumerable PluginIds { get; set; } - - public ContextSlice Map() - { - return new ContextSlice(Model, PluginIds); - } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGenerateClasses.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGenerateClasses.cs deleted file mode 100644 index aedb15dc..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGenerateClasses.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public record RestGenerateClasses(List Languages, string? TransferFormat = null); diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetContextResponse.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetContextResponse.cs deleted file mode 100644 index b6abf2ca..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetContextResponse.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public record RestGetContextResponse(IEnumerable Data); diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetInstalledPluginsResponse.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetInstalledPluginsResponse.cs deleted file mode 100644 index f2f51151..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestGetInstalledPluginsResponse.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public record RestGetInstalledPluginsResponse(IEnumerable Data); diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstallPlugin.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstallPlugin.cs deleted file mode 100644 index 76ab41ef..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstallPlugin.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public class RestInstallPlugin -{ - public required string PluginId { get; set; } - public required string Version { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPlugin.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPlugin.cs deleted file mode 100644 index ec656ab6..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPlugin.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ScriptBee.Domain.Model.Plugins; - -namespace ScriptBee.Rest.Contracts; - -public class RestInstalledPlugin -{ - public string FolderPath { get; set; } = null!; - public string Id { get; set; } = null!; - public string Version { get; set; } = null!; - public RestInstalledPluginManifest Manifest { get; set; } = null!; - - public Plugin Map() - { - return new Plugin(FolderPath, new PluginId(Id, new Version(Version)), Manifest.Map()); - } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPluginManifest.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPluginManifest.cs deleted file mode 100644 index 3ed1b471..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestInstalledPluginManifest.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ScriptBee.Domain.Model.Plugins.Manifest; - -namespace ScriptBee.Rest.Contracts; - -public class RestInstalledPluginManifest -{ - public required string ApiVersion { get; set; } - public required string Name { get; set; } - public string? Description { get; set; } - public string? Author { get; set; } - public required List ExtensionPoints { get; set; } = []; - - public PluginManifest Map() - { - return new PluginManifest - { - ApiVersion = ApiVersion, - Name = Name, - Description = Description, - Author = Author, - ExtensionPoints = ExtensionPoints - .Select(ep => ep.Map()) - .Where(ep => ep != null) - .Cast() - .ToList(), - }; - } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestPluginExtensionPoint.cs deleted file mode 100644 index b5b5b4bc..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestPluginExtensionPoint.cs +++ /dev/null @@ -1,116 +0,0 @@ -using ScriptBee.Domain.Model.Plugins.Manifest; - -namespace ScriptBee.Rest.Contracts; - -public class RestPluginExtensionPoint -{ - public string Kind { get; set; } = ""; - public string EntryPoint { get; set; } = ""; - public string Version { get; set; } = ""; - - public string? Language { get; set; } - public string? Extension { get; set; } - - public string? RemoteEntry { get; set; } - public string? RemoteName { get; set; } - public IEnumerable? Outlets { get; set; } - - public PluginExtensionPoint? Map() - { - return Kind switch - { - PluginKind.Loader => new LoaderPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - }, - PluginKind.Linker => new LinkerPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - }, - PluginKind.HelperFunctions => new HelperFunctionsPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - }, - PluginKind.ScriptGenerator => new ScriptGeneratorPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - Language = Language!, - Extension = Extension!, - }, - PluginKind.ScriptRunner => new ScriptRunnerPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - Language = Language!, - Extension = Extension!, - }, - PluginKind.Ui => new UiPluginExtensionPoint - { - Kind = Kind, - EntryPoint = EntryPoint, - Version = Version, - RemoteName = RemoteName!, - RemoteEntry = RemoteEntry!, - Outlets = (Outlets ?? []).Select(MapOutlet), - }, - _ => null, - }; - } - - private static UiPluginExtensionPointOutlet MapOutlet(RestUiPluginExtensionPointOutlet outlet) - { - return outlet.Type switch - { - "top-navigation-bar" => new TopNavigationBarOutlet - { - Type = outlet.Type, - ExposedModule = outlet.ExposedModule, - Path = outlet.Path ?? "", - Label = outlet.Label ?? "", - Nested = outlet.Nested, - ComponentName = outlet.ComponentName, - }, - "side-panel" => new SidePanelOutlet - { - Type = outlet.Type, - ExposedModule = outlet.ExposedModule, - Path = outlet.Path ?? "", - Label = outlet.Label ?? "", - Nested = outlet.Nested, - ComponentName = outlet.ComponentName, - Icon = outlet.Icon ?? "", - }, - "file-previewer" => new FilePreviewerOutlet - { - Type = outlet.Type, - ExposedModule = outlet.ExposedModule, - Label = outlet.Label ?? "", - ComponentName = outlet.ComponentName, - Icon = outlet.Icon, - SupportedFileExtensions = outlet.SupportedFileExtensions, - }, - _ => new UiPluginExtensionPointOutlet { Type = outlet.Type }, - }; - } -} - -public class RestUiPluginExtensionPointOutlet -{ - public required string Type { get; set; } - public required string ExposedModule { get; set; } - public string? Path { get; set; } - public string? Label { get; set; } - public bool? Nested { get; set; } - public string? ComponentName { get; set; } - public string? Icon { get; set; } - public List? SupportedFileExtensions { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisCommand.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisCommand.cs deleted file mode 100644 index 46fdb20e..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisCommand.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public class RestRunAnalysisCommand -{ - public required string ProjectId { get; set; } - public required string ScriptId { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisResponse.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisResponse.cs deleted file mode 100644 index 6c7d9fd8..00000000 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Contracts/RestRunAnalysisResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ScriptBee.Rest.Contracts; - -public class RestRunAnalysisResponse -{ - public required string Id { get; set; } - public required string ProjectId { get; set; } - public required string ScriptId { get; set; } - public required string Status { get; set; } - public required DateTimeOffset CreationDate { get; set; } -} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Converters/JsonStringEnumMemberConverterFactory.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Converters/JsonStringEnumMemberConverterFactory.cs new file mode 100644 index 00000000..8ec292c8 --- /dev/null +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Converters/JsonStringEnumMemberConverterFactory.cs @@ -0,0 +1,81 @@ +using System.Reflection; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ScriptBee.Rest.Converters; + +public sealed class JsonStringEnumMemberConverterFactory : JsonConverterFactory +{ + public override bool CanConvert(Type typeToConvert) + { + typeToConvert = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert; + return typeToConvert.IsEnum; + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + var enumType = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert; + + var converterType = typeof(EnumMemberConverter<>).MakeGenericType(enumType); + return (JsonConverter)Activator.CreateInstance(converterType)!; + } + + private sealed class EnumMemberConverter : JsonConverter + where TEnum : struct, Enum + { + private static readonly Dictionary ReadMap; + private static readonly Dictionary WriteMap; + + static EnumMemberConverter() + { + ReadMap = new(StringComparer.Ordinal); + WriteMap = new(); + + foreach ( + var field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static) + ) + { + var value = (TEnum)field.GetValue(null)!; + + var enumMember = field.GetCustomAttribute(); + + var text = enumMember?.Value ?? field.Name; + + ReadMap[text] = value; + WriteMap[value] = text; + } + } + + public override TEnum Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var value = reader.GetString(); + + if (value is not null && ReadMap.TryGetValue(value, out var result)) + { + return result; + } + + throw new JsonException($"Unable to convert '{value}' to {typeof(TEnum).Name}."); + } + + public override void Write( + Utf8JsonWriter writer, + TEnum value, + JsonSerializerOptions options + ) + { + if (WriteMap.TryGetValue(value, out var text)) + { + writer.WriteStringValue(text); + return; + } + + writer.WriteStringValue(value.ToString()); + } + } +} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/DeserializationUtils.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/DeserializationUtils.cs new file mode 100644 index 00000000..4e76a7e1 --- /dev/null +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/DeserializationUtils.cs @@ -0,0 +1,14 @@ +using System.Text.Json; + +namespace ScriptBee.Rest; + +public class DeserializationUtils +{ + public static T ConvertTo(object value) + { + if (value is JsonElement element) + return element.Deserialize()!; + + return JsonSerializer.Deserialize(JsonSerializer.Serialize(value))!; + } +} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GenerateInstanceClassesAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GenerateInstanceClassesAdapter.cs index 7fc35681..74645eee 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GenerateInstanceClassesAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GenerateInstanceClassesAdapter.cs @@ -1,8 +1,8 @@ using Refit; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; -using ScriptBee.Rest.Contracts; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -19,10 +19,10 @@ CancellationToken cancellationToken var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var analysisApi = RestService.For(client); - return await contextApi.GenerateClasses( - new RestGenerateClasses(languages, transferFormat), + return await analysisApi.GenerateClasses( + new GenerateClassesRequest(languages, transferFormat ?? string.Empty), cancellationToken ); } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Generated/AnalysisApi.g.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Generated/AnalysisApi.g.cs new file mode 100644 index 00000000..99216487 --- /dev/null +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Generated/AnalysisApi.g.cs @@ -0,0 +1,1414 @@ +// +// This code was generated by Refitter. +// + + +using Refit; +using System.Collections.Generic; +using System.Text.Json.Serialization; +using System.Threading; +using System.Threading.Tasks; +using ScriptBee.Rest.Api.Generated.Contracts; + +#nullable enable annotations + +namespace ScriptBee.Rest.Api.Generated +{ + /// ScriptBee Analysis API + [System.CodeDom.Compiler.GeneratedCode("Refitter", "2.0.0.0")] + public partial interface IAnalysisApi + { + /// Get installed plugins + /// Retrieves a list of all plugins currently installed in the analysis service. + /// The cancellation token to cancel the request. + /// OK + /// Thrown when the request returns a non-success status code. + [Headers("Accept: application/json")] + [Get("/api/plugins")] + Task PluginsGet(CancellationToken cancellationToken = default); + + /// Install a plugin + /// Installs a specific plugin version into the analysis service. + /// body parameter + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// + /// Thrown when the request returns a non-success status code: + /// + /// + /// Status + /// Description + /// + /// + /// 400 + /// Bad Request + /// + /// + /// 500 + /// Internal Server Error + /// + /// + /// + [Headers("Accept: application/problem+json, application/json", "Content-Type: application/json")] + [Post("/api/plugins")] + Task PluginsPost([Body] InstallPluginCommand body, CancellationToken cancellationToken = default); + + /// Uninstall a plugin + /// Uninstalls a specific plugin version from the analysis service. + /// pluginId parameter + /// version parameter + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// Thrown when the request returns a non-success status code. + [Delete("/api/plugins/{pluginId}")] + Task PluginsDelete(string pluginId, [Query] string version, CancellationToken cancellationToken = default); + + /// Clear analysis context + /// Clears all data from the current analysis context. + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// Thrown when the request returns a non-success status code. + [Post("/api/context/clear")] + Task Clear(CancellationToken cancellationToken = default); + + /// Generate classes for analysis context + /// Generates script classes based on the current data context and returns them as a stream. + /// body parameter + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// Thrown when the request returns a non-success status code. + [Headers("Content-Type: application/json")] + [Post("/api/context/generate-classes")] + Task GenerateClasses([Body] GenerateClassesRequest body, CancellationToken cancellationToken = default); + + /// Get analysis context + /// Retrieves the current data context from the analysis service. + /// The cancellation token to cancel the request. + /// OK + /// Thrown when the request returns a non-success status code. + [Headers("Accept: application/json")] + [Get("/api/context")] + Task Context(CancellationToken cancellationToken = default); + + /// Search context nodes + /// Searches for context nodes based on a query string. + /// query parameter + /// offset parameter + /// limit parameter + /// The cancellation token to cancel the request. + /// OK + /// Thrown when the request returns a non-success status code. + [Headers("Accept: application/json")] + [Get("/api/context/graph-nodes")] + Task GraphNodes([Query] string query, [Query] int? offset, [Query] int? limit, CancellationToken cancellationToken = default); + + /// Get node neighbors + /// Retrieves the immediate neighbors and edges for a specific context node. + /// nodeId parameter + /// The cancellation token to cancel the request. + /// OK + /// Thrown when the request returns a non-success status code. + [Headers("Accept: application/json")] + [Get("/api/context/graph-nodes/{nodeId}/neighbors")] + Task Neighbors(string nodeId, CancellationToken cancellationToken = default); + + /// Link analysis context + /// Links the current analysis context using the provided linkers. + /// body parameter + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// + /// Thrown when the request returns a non-success status code: + /// + /// + /// Status + /// Description + /// + /// + /// 400 + /// Bad Request + /// + /// + /// + [Headers("Accept: application/problem+json", "Content-Type: application/json")] + [Post("/api/context/link")] + Task Link([Body] LinkContextCommand body, CancellationToken cancellationToken = default); + + /// Load data into analysis context + /// Loads data from files into the current analysis context using the provided loaders. + /// body parameter + /// The cancellation token to cancel the request. + /// A that completes when the request is finished. + /// + /// Thrown when the request returns a non-success status code: + /// + /// + /// Status + /// Description + /// + /// + /// 400 + /// Bad Request + /// + /// + /// + [Headers("Accept: application/problem+json", "Content-Type: application/json")] + [Post("/api/context/load")] + Task Load([Body] LoadContextCommand body, CancellationToken cancellationToken = default); + + /// Run analysis + /// Starts the execution of an analysis script on the analysis service. + /// body parameter + /// The cancellation token to cancel the request. + /// Accepted + /// + /// Thrown when the request returns a non-success status code: + /// + /// + /// Status + /// Description + /// + /// + /// 400 + /// Bad Request + /// + /// + /// + [Headers("Accept: application/json, application/problem+json", "Content-Type: application/json")] + [Post("/api/analyses")] + Task Analyses([Body] RunAnalysisCommand body, CancellationToken cancellationToken = default); + + + } + +} + +//---------------------- +// +// Generated using the NSwag toolchain v14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" +#pragma warning disable 649 // Disable "CS0649 Field is never assigned to, and will always have its default value null" +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." +#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" +#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" +#pragma warning disable 8600 // Disable "CS8600 Converting null literal or possible null value to non-nullable type" +#pragma warning disable 8602 // Disable "CS8602 Dereference of a possibly null reference" +#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" +#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" +#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" +#pragma warning disable 8765 // Disable "CS8765 Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes)." + +namespace ScriptBee.Rest.Api.Generated.Contracts +{ + using System = global::System; + + + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record ContextGraphEdge + { + [JsonConstructor] + public ContextGraphEdge(string @label, string @source, string @target) + { + this.Source = @source; + this.Target = @target; + this.Label = @label; + } + + [JsonPropertyName("source")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Source { get; init; } + + [JsonPropertyName("target")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Target { get; init; } + + [JsonPropertyName("label")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Label { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record ContextGraphNode + { + [JsonConstructor] + public ContextGraphNode(string @id, string @label, string @loader, object @properties, string @type) + { + this.Id = @id; + this.Label = @label; + this.Type = @type; + this.Loader = @loader; + this.Properties = @properties; + } + + [JsonPropertyName("id")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; init; } + + [JsonPropertyName("label")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Label { get; init; } + + [JsonPropertyName("type")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Type { get; init; } + + [JsonPropertyName("loader")] + public string Loader { get; init; } + + [JsonPropertyName("properties")] + [System.ComponentModel.DataAnnotations.Required] + public object Properties { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record ContextGraphResponse + { + [JsonConstructor] + public ContextGraphResponse(ICollection @edges, ICollection @nodes) + { + this.Nodes = @nodes; + this.Edges = @edges; + } + + [JsonPropertyName("nodes")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection Nodes { get; init; } + + [JsonPropertyName("edges")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection Edges { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record ContextSlice + { + [JsonConstructor] + public ContextSlice(string @model, ICollection @pluginIds) + { + this.Model = @model; + this.PluginIds = @pluginIds; + } + + [JsonPropertyName("model")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Model { get; init; } + + [JsonPropertyName("pluginIds")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection PluginIds { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record GenerateClassesRequest + { + [JsonConstructor] + public GenerateClassesRequest(ICollection @languages, string @transferFormat) + { + this.Languages = @languages; + this.TransferFormat = @transferFormat; + } + + [JsonPropertyName("languages")] + public ICollection Languages { get; init; } + + [JsonPropertyName("transferFormat")] + public string TransferFormat { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record GetContextResponse + { + [JsonConstructor] + public GetContextResponse(ICollection @data) + { + this.Data = @data; + } + + [JsonPropertyName("data")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection Data { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record GetInstalledPluginsResponse + { + [JsonConstructor] + public GetInstalledPluginsResponse(ICollection @data) + { + this.Data = @data; + } + + [JsonPropertyName("data")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection Data { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record HttpValidationProblemDetails + { + [JsonConstructor] + public HttpValidationProblemDetails(string @detail, IDictionary> @errors, string @instance, int? @status, string @title, string @type) + { + this.Type = @type; + this.Title = @title; + this.Status = @status; + this.Detail = @detail; + this.Instance = @instance; + this.Errors = @errors; + } + + [JsonPropertyName("type")] + public string Type { get; init; } + + [JsonPropertyName("title")] + public string Title { get; init; } + + [JsonPropertyName("status")] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^-?(?:0|[1-9]\d*)$")] + public int? Status { get; init; } + + [JsonPropertyName("detail")] + public string Detail { get; init; } + + [JsonPropertyName("instance")] + public string Instance { get; init; } + + [JsonPropertyName("errors")] + public IDictionary> Errors { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPlugin + { + [JsonConstructor] + public InstalledPlugin(string @folderPath, string @id, InstalledPluginManifest @manifest, string @version) + { + this.FolderPath = @folderPath; + this.Id = @id; + this.Version = @version; + this.Manifest = @manifest; + } + + [JsonPropertyName("folderPath")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string FolderPath { get; init; } + + [JsonPropertyName("id")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + [JsonPropertyName("manifest")] + [System.ComponentModel.DataAnnotations.Required] + public InstalledPluginManifest Manifest { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Base class for outlets of a plugin extension point. + /// + [JsonInheritanceConverter(typeof(InstalledPluginExtensionPointOutletBase), "type")] + [JsonInheritanceAttribute("top-navigation-bar", typeof(InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet))] + [JsonInheritanceAttribute("side-panel", typeof(InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet))] + [JsonInheritanceAttribute("file-previewer", typeof(InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet))] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPluginExtensionPointOutletBase + { + [JsonConstructor] + public InstalledPluginExtensionPointOutletBase() + { + } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Represents a component for file previewer of output results. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet : InstalledPluginExtensionPointOutletBase + { + [JsonConstructor] + public InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet(string @componentName, string @exposedModule, string @icon, string @label, ICollection @supportedFileExtensions, InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutletType @type) + : base() + { + this.Type = @type; + this.ExposedModule = @exposedModule; + this.Label = @label; + this.ComponentName = @componentName; + this.Icon = @icon; + this.SupportedFileExtensions = @supportedFileExtensions; + } + + [JsonPropertyName("type")] +public InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutletType Type { get; init; } + + [JsonPropertyName("exposedModule")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ExposedModule { get; init; } + + [JsonPropertyName("label")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Label { get; init; } + + [JsonPropertyName("componentName")] + public string ComponentName { get; init; } + + [JsonPropertyName("icon")] + public string Icon { get; init; } + + [JsonPropertyName("supportedFileExtensions")] + public ICollection SupportedFileExtensions { get; init; } + + } + + /// + /// Represents an element from the Side Hamburger Panel with route. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet : InstalledPluginExtensionPointOutletBase + { + [JsonConstructor] + public InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet(string @componentName, string @exposedModule, string @icon, string @label, bool? @nested, string @path, InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutletType @type) + : base() + { + this.Type = @type; + this.ExposedModule = @exposedModule; + this.Label = @label; + this.Path = @path; + this.Nested = @nested; + this.ComponentName = @componentName; + this.Icon = @icon; + } + + [JsonPropertyName("type")] +public InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutletType Type { get; init; } + + [JsonPropertyName("exposedModule")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ExposedModule { get; init; } + + [JsonPropertyName("label")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Label { get; init; } + + [JsonPropertyName("path")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Path { get; init; } + + [JsonPropertyName("nested")] + public bool? Nested { get; init; } + + [JsonPropertyName("componentName")] + public string ComponentName { get; init; } + + [JsonPropertyName("icon")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Icon { get; init; } + + } + + /// + /// Represents an element from the Top Navigation Bar with route. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet : InstalledPluginExtensionPointOutletBase + { + [JsonConstructor] + public InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet(string @componentName, string @exposedModule, string @label, bool? @nested, string @path, InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutletType @type) + : base() + { + this.Type = @type; + this.ExposedModule = @exposedModule; + this.Label = @label; + this.Path = @path; + this.Nested = @nested; + this.ComponentName = @componentName; + } + + [JsonPropertyName("type")] +public InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutletType Type { get; init; } + + [JsonPropertyName("exposedModule")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ExposedModule { get; init; } + + [JsonPropertyName("label")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Label { get; init; } + + [JsonPropertyName("path")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Path { get; init; } + + [JsonPropertyName("nested")] + public bool? Nested { get; init; } + + [JsonPropertyName("componentName")] + public string ComponentName { get; init; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstalledPluginManifest + { + [JsonConstructor] + public InstalledPluginManifest(string @apiVersion, string @author, string @description, ICollection @extensionPoints, string @name) + { + this.ApiVersion = @apiVersion; + this.Name = @name; + this.Description = @description; + this.Author = @author; + this.ExtensionPoints = @extensionPoints; + } + + [JsonPropertyName("apiVersion")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ApiVersion { get; init; } + + [JsonPropertyName("name")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Name { get; init; } + + [JsonPropertyName("description")] + public string Description { get; init; } + + [JsonPropertyName("author")] + public string Author { get; init; } + + [JsonPropertyName("extensionPoints")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection ExtensionPoints { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record InstallPluginCommand + { + [JsonConstructor] + public InstallPluginCommand(string @pluginId, string @version) + { + this.PluginId = @pluginId; + this.Version = @version; + } + + [JsonPropertyName("pluginId")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string PluginId { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record LinkContextCommand + { + [JsonConstructor] + public LinkContextCommand(ICollection @linkerIds) + { + this.LinkerIds = @linkerIds; + } + + [JsonPropertyName("linkerIds")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection LinkerIds { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record LoadContextCommand + { + [JsonConstructor] + public LoadContextCommand(IDictionary> @filesToLoad) + { + this.FilesToLoad = @filesToLoad; + } + + [JsonPropertyName("filesToLoad")] + [System.ComponentModel.DataAnnotations.Required] + public IDictionary> FilesToLoad { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Base class for plugin extension points + /// + [JsonInheritanceConverter(typeof(PluginExtensionPoint), "kind")] + [JsonInheritanceAttribute("Plugin", typeof(PluginExtensionPointNestedPluginExtensionPoint))] + [JsonInheritanceAttribute("Loader", typeof(PluginExtensionPointLoaderPluginExtensionPoint))] + [JsonInheritanceAttribute("Linker", typeof(PluginExtensionPointLinkerPluginExtensionPoint))] + [JsonInheritanceAttribute("ScriptGenerator", typeof(PluginExtensionPointScriptGeneratorPluginExtensionPoint))] + [JsonInheritanceAttribute("ScriptRunner", typeof(PluginExtensionPointScriptRunnerPluginExtensionPoint))] + [JsonInheritanceAttribute("HelperFunctions", typeof(PluginExtensionPointHelperFunctionsPluginExtensionPoint))] + [JsonInheritanceAttribute("UI", typeof(PluginExtensionPointUiPluginExtensionPoint))] + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPoint() + { + } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Represents a helper functions plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointHelperFunctionsPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointHelperFunctionsPluginExtensionPoint(string @entryPoint, PluginExtensionPointHelperFunctionsPluginExtensionPointKind @kind, string @version) + : base() + { + this.Kind = @kind; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointHelperFunctionsPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a linker plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointLinkerPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointLinkerPluginExtensionPoint(string @entryPoint, PluginExtensionPointLinkerPluginExtensionPointKind @kind, string @version) + : base() + { + this.Kind = @kind; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointLinkerPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a loader plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointLoaderPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointLoaderPluginExtensionPoint(string @entryPoint, PluginExtensionPointLoaderPluginExtensionPointKind @kind, string @version) + : base() + { + this.Kind = @kind; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointLoaderPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a plugin from a bundle. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointNestedPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointNestedPluginExtensionPoint(string @entryPoint, PluginExtensionPointNestedPluginExtensionPointKind @kind, string @version) + : base() + { + this.Kind = @kind; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointNestedPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a script generator plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointScriptGeneratorPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointScriptGeneratorPluginExtensionPoint(string @entryPoint, string @extension, PluginExtensionPointScriptGeneratorPluginExtensionPointKind @kind, string @language, string @version) + : base() + { + this.Kind = @kind; + this.Language = @language; + this.Extension = @extension; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointScriptGeneratorPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("language")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Language { get; init; } + + [JsonPropertyName("extension")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Extension { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a script runner plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointScriptRunnerPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointScriptRunnerPluginExtensionPoint(string @entryPoint, string @extension, PluginExtensionPointScriptRunnerPluginExtensionPointKind @kind, string @language, string @version) + : base() + { + this.Kind = @kind; + this.Language = @language; + this.Extension = @extension; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointScriptRunnerPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("language")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Language { get; init; } + + [JsonPropertyName("extension")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Extension { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + /// + /// Represents a UI plugin extension point. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record PluginExtensionPointUiPluginExtensionPoint : PluginExtensionPoint + { + [JsonConstructor] + public PluginExtensionPointUiPluginExtensionPoint(string @entryPoint, PluginExtensionPointUiPluginExtensionPointKind @kind, ICollection @outlets, string @remoteEntry, string @remoteName, string @version) + : base() + { + this.Kind = @kind; + this.RemoteName = @remoteName; + this.RemoteEntry = @remoteEntry; + this.Outlets = @outlets; + this.EntryPoint = @entryPoint; + this.Version = @version; + } + + [JsonPropertyName("kind")] +public PluginExtensionPointUiPluginExtensionPointKind Kind { get; init; } + + [JsonPropertyName("remoteName")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string RemoteName { get; init; } + + [JsonPropertyName("remoteEntry")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string RemoteEntry { get; init; } + + [JsonPropertyName("outlets")] + [System.ComponentModel.DataAnnotations.Required] + public ICollection Outlets { get; init; } + + [JsonPropertyName("entryPoint")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string EntryPoint { get; init; } + + [JsonPropertyName("version")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Version { get; init; } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record ProblemDetails + { + [JsonConstructor] + public ProblemDetails(string @detail, string @instance, int? @status, string @title, string @type) + { + this.Type = @type; + this.Title = @title; + this.Status = @status; + this.Detail = @detail; + this.Instance = @instance; + } + + [JsonPropertyName("type")] + public string Type { get; init; } + + [JsonPropertyName("title")] + public string Title { get; init; } + + [JsonPropertyName("status")] + [System.ComponentModel.DataAnnotations.RegularExpression(@"^-?(?:0|[1-9]\d*)$")] + public int? Status { get; init; } + + [JsonPropertyName("detail")] + public string Detail { get; init; } + + [JsonPropertyName("instance")] + public string Instance { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + /// + /// Command used to run an analysis script on the analysis service. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record RunAnalysisCommand + { + [JsonConstructor] + public RunAnalysisCommand(string @projectId, string @scriptId) + { + this.ProjectId = @projectId; + this.ScriptId = @scriptId; + } + + [JsonPropertyName("projectId")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ProjectId { get; init; } + + [JsonPropertyName("scriptId")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ScriptId { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + public partial record RunAnalysisResponse + { + [JsonConstructor] + public RunAnalysisResponse(System.DateTimeOffset @creationDate, string @id, string @projectId, string @scriptId, string @status) + { + this.Id = @id; + this.ProjectId = @projectId; + this.ScriptId = @scriptId; + this.Status = @status; + this.CreationDate = @creationDate; + } + + [JsonPropertyName("id")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Id { get; init; } + + [JsonPropertyName("projectId")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ProjectId { get; init; } + + [JsonPropertyName("scriptId")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string ScriptId { get; init; } + + [JsonPropertyName("status")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Status { get; init; } + + [JsonPropertyName("creationDate")] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.DateTimeOffset CreationDate { get; init; } + + private IDictionary _additionalProperties; + + [JsonExtensionData] + public IDictionary AdditionalProperties + { + get { return _additionalProperties ?? (_additionalProperties = new Dictionary()); } + set { _additionalProperties = value; } + } + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutletType + { + + [System.Runtime.Serialization.EnumMember(Value = @"file-previewer")] + FilePreviewer = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutletType + { + + [System.Runtime.Serialization.EnumMember(Value = @"side-panel")] + SidePanel = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutletType + { + + [System.Runtime.Serialization.EnumMember(Value = @"top-navigation-bar")] + TopNavigationBar = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointHelperFunctionsPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"HelperFunctions")] + HelperFunctions = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointLinkerPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"Linker")] + Linker = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointLoaderPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"Loader")] + Loader = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointNestedPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"Plugin")] + Plugin = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointScriptGeneratorPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"ScriptGenerator")] + ScriptGenerator = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointScriptRunnerPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"ScriptRunner")] + ScriptRunner = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum PluginExtensionPointUiPluginExtensionPointKind + { + + [System.Runtime.Serialization.EnumMember(Value = @"UI")] + UI = 0, + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = true)] + internal class JsonInheritanceAttribute : System.Attribute + { + public JsonInheritanceAttribute(string key, System.Type type) + { + Key = key; + Type = type; + } + + public string Key { get; } + + public System.Type Type { get; } + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))")] + internal class JsonInheritanceConverterAttribute : JsonConverterAttribute + { + public string DiscriminatorName { get; } + + public JsonInheritanceConverterAttribute(System.Type baseType, string discriminatorName = "discriminator") + : base(typeof(JsonInheritanceConverter<>).MakeGenericType(baseType)) + { + DiscriminatorName = discriminatorName; + } + } + + public class JsonInheritanceConverter : JsonConverter + { + private readonly string _discriminatorName; + + public JsonInheritanceConverter() + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(typeof(TBase)); + _discriminatorName = attribute?.DiscriminatorName ?? "discriminator"; + } + + public JsonInheritanceConverter(string discriminatorName) + { + _discriminatorName = discriminatorName; + } + + public string DiscriminatorName { get { return _discriminatorName; } } + + public override TBase Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) + { + var document = System.Text.Json.JsonDocument.ParseValue(ref reader); + var hasDiscriminator = document.RootElement.TryGetProperty(_discriminatorName, out var discriminator); + var subtype = GetDiscriminatorType(document.RootElement, typeToConvert, hasDiscriminator ? discriminator.GetString() : null); + + var bufferWriter = new System.IO.MemoryStream(); + using (var writer = new System.Text.Json.Utf8JsonWriter(bufferWriter)) + { + document.RootElement.WriteTo(writer); + } + + return (TBase)System.Text.Json.JsonSerializer.Deserialize(bufferWriter.ToArray(), subtype, options); + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, TBase value, System.Text.Json.JsonSerializerOptions options) + { + if (value != null) + { + writer.WriteStartObject(); + writer.WriteString(_discriminatorName, GetDiscriminatorValue(value.GetType())); + + var bytes = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes((object)value, options); + var document = System.Text.Json.JsonDocument.Parse(bytes); + foreach (var property in document.RootElement.EnumerateObject()) + { + property.WriteTo(writer); + } + + writer.WriteEndObject(); + } + else + { + writer.WriteNullValue(); + } + } + + public string GetDiscriminatorValue(System.Type type) + { + var jsonInheritanceAttributeDiscriminator = GetSubtypeDiscriminator(type); + if (jsonInheritanceAttributeDiscriminator != null) + { + return jsonInheritanceAttributeDiscriminator; + } + + return type.Name; + } + + protected System.Type GetDiscriminatorType(System.Text.Json.JsonElement jObject, System.Type objectType, string discriminatorValue) + { + if (discriminatorValue != null) + { + var jsonInheritanceAttributeSubtype = GetObjectSubtype(objectType, discriminatorValue); + if (jsonInheritanceAttributeSubtype != null) + { + return jsonInheritanceAttributeSubtype; + } + + if (objectType.Name == discriminatorValue) + { + return objectType; + } + + var typeName = objectType.Namespace + "." + discriminatorValue; + var subtype = System.Reflection.IntrospectionExtensions.GetTypeInfo(objectType).Assembly.GetType(typeName); + if (subtype != null) + { + return subtype; + } + } + + throw new System.InvalidOperationException("Could not find subtype of '" + objectType.Name + "' with discriminator '" + discriminatorValue + "'."); + } + + private System.Type GetObjectSubtype(System.Type baseType, string discriminatorValue) + { + foreach (var attribute in System.Reflection.CustomAttributeExtensions.GetCustomAttributes(System.Reflection.IntrospectionExtensions.GetTypeInfo(baseType), true)) + { + if (attribute.Key == discriminatorValue) + return attribute.Type; + } + + return null; + } + + private string GetSubtypeDiscriminator(System.Type objectType) + { + foreach (var attribute in System.Reflection.CustomAttributeExtensions.GetCustomAttributes(System.Reflection.IntrospectionExtensions.GetTypeInfo(objectType), true)) + { + if (attribute.Type == objectType) + return attribute.Key; + } + + return null; + } + } + + +} + +#pragma warning restore 108 +#pragma warning restore 114 +#pragma warning restore 472 +#pragma warning restore 612 +#pragma warning restore 649 +#pragma warning restore 1573 +#pragma warning restore 1591 +#pragma warning restore 8073 +#pragma warning restore 3016 +#pragma warning restore 8600 +#pragma warning restore 8602 +#pragma warning restore 8603 +#pragma warning restore 8604 +#pragma warning restore 8625 +#pragma warning restore 8765 \ No newline at end of file diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextAdapter.cs index 7108f36f..cab016f5 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextAdapter.cs @@ -2,7 +2,8 @@ using ScriptBee.Domain.Model.Context; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; +using ScriptBee.Rest.Api.Generated; +using GeneratedContracts = ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -16,9 +17,14 @@ public async Task> Get( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var analysisApi = RestService.For(client); - var response = await contextApi.Get(cancellationToken); - return response.Data.Select(s => s.Map()); + var response = await analysisApi.Context(cancellationToken); + return response.Data.Select(MapContextSlice); + } + + private static ContextSlice MapContextSlice(GeneratedContracts.ContextSlice slice) + { + return new ContextSlice(slice.Model, slice.PluginIds); } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextGraphAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextGraphAdapter.cs index fa0a96b9..6b269e6c 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextGraphAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetInstanceContextGraphAdapter.cs @@ -2,7 +2,8 @@ using ScriptBee.Domain.Model.Context; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; +using ScriptBee.Rest.Api.Generated; +using GeneratedContracts = ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -17,13 +18,18 @@ public async Task SearchNodes( CancellationToken cancellationToken ) { - var contextApi = GetContextApi(instanceInfo); + var analysisApi = GetAnalysisApi(instanceInfo); - var response = await contextApi.SearchNodes(query, offset, limit, cancellationToken); + var response = await analysisApi.GraphNodes( + query ?? string.Empty, + offset, + limit, + cancellationToken + ); return new ContextGraphResult( - response.Nodes.Select(node => node.Map()), - response.Edges.Select(edge => edge.Map()) + response.Nodes.Select(MapNode), + response.Edges.Select(MapEdge) ); } @@ -33,21 +39,37 @@ public async Task GetNeighbors( CancellationToken cancellationToken ) { - var contextApi = GetContextApi(instanceInfo); + var analysisApi = GetAnalysisApi(instanceInfo); - var response = await contextApi.GetNeighbors(nodeId, cancellationToken); + var response = await analysisApi.Neighbors(nodeId, cancellationToken); return new ContextGraphResult( - response.Nodes.Select(node => node.Map()), - response.Edges.Select(edge => edge.Map()) + response.Nodes.Select(MapNode), + response.Edges.Select(MapEdge) ); } - private IContextApi GetContextApi(InstanceInfo instanceInfo) + private IAnalysisApi GetAnalysisApi(InstanceInfo instanceInfo) { var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - return RestService.For(client); + return RestService.For(client); + } + + private static ContextGraphNode MapNode(GeneratedContracts.ContextGraphNode node) + { + return new ContextGraphNode( + node.Id, + node.Label, + node.Type, + node.Loader, + DeserializationUtils.ConvertTo>(node.Properties) + ); + } + + private static ContextGraphEdge MapEdge(GeneratedContracts.ContextGraphEdge edge) + { + return new ContextGraphEdge(edge.Source, edge.Target, edge.Label); } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetPluginsAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetPluginsAdapter.cs index 72b78cb3..35584dc7 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetPluginsAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/GetPluginsAdapter.cs @@ -1,8 +1,14 @@ +using System.Text.Json; using Refit; using ScriptBee.Domain.Model.Instance; using ScriptBee.Domain.Model.Plugins; +using ScriptBee.Domain.Model.Plugins.Manifest; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; +using ScriptBee.Rest.Converters; +using PluginExtensionPoint = ScriptBee.Domain.Model.Plugins.Manifest.PluginExtensionPoint; +using RestPluginExtensionPoint = ScriptBee.Rest.Api.Generated.Contracts.PluginExtensionPoint; namespace ScriptBee.Rest; @@ -16,10 +22,158 @@ CancellationToken cancellationToken var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var pluginsApi = RestService.For(client); + var pluginsApi = GetAnalysisApiWithCustomConverter(client); - var response = await pluginsApi.GetInstalledPlugins(cancellationToken); + var response = await pluginsApi.PluginsGet(cancellationToken); - return response.Data.Select(plugin => plugin.Map()); + return response.Data.Select(MapPlugin); + } + + private static IAnalysisApi GetAnalysisApiWithCustomConverter(HttpClient client) + { + var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); + + options.Converters.Insert(0, new JsonStringEnumMemberConverterFactory()); + + var settings = new RefitSettings + { + ContentSerializer = new SystemTextJsonContentSerializer(options), + }; + var pluginsApi = RestService.For(client, settings); + return pluginsApi; + } + + private static Plugin MapPlugin(InstalledPlugin plugin) + { + return new Plugin( + plugin.FolderPath, + new PluginId(plugin.Id, new Version(plugin.Version)), + MapManifest(plugin.Manifest) + ); + } + + private static PluginManifest MapManifest(InstalledPluginManifest manifest) + { + var extensionPoints = manifest + .ExtensionPoints.Select(MapExtensionPoint) + .OfType() + .ToList(); + + return new PluginManifest + { + ApiVersion = manifest.ApiVersion, + Name = manifest.Name, + Description = manifest.Description, + Author = manifest.Author, + ExtensionPoints = extensionPoints, + }; + } + + private static PluginExtensionPoint? MapExtensionPoint(RestPluginExtensionPoint ep) + { + return ep switch + { + PluginExtensionPointLoaderPluginExtensionPoint point => new LoaderPluginExtensionPoint + { + Kind = PluginKind.Loader, + EntryPoint = point.EntryPoint, + Version = point.Version, + }, + PluginExtensionPointLinkerPluginExtensionPoint point => new LinkerPluginExtensionPoint + { + Kind = PluginKind.Linker, + EntryPoint = point.EntryPoint, + Version = point.Version, + }, + PluginExtensionPointHelperFunctionsPluginExtensionPoint point => + new HelperFunctionsPluginExtensionPoint + { + Kind = PluginKind.HelperFunctions, + EntryPoint = point.EntryPoint, + Version = point.Version, + }, + PluginExtensionPointNestedPluginExtensionPoint point => new PluginBundleExtensionPoint + { + Kind = PluginKind.Plugin, + EntryPoint = point.EntryPoint, + Version = point.Version, + }, + PluginExtensionPointScriptGeneratorPluginExtensionPoint point => + new ScriptGeneratorPluginExtensionPoint + { + Kind = PluginKind.ScriptGenerator, + EntryPoint = point.EntryPoint, + Version = point.Version, + Language = point.Language, + Extension = point.Extension, + }, + PluginExtensionPointScriptRunnerPluginExtensionPoint point => + new ScriptRunnerPluginExtensionPoint + { + Kind = PluginKind.ScriptRunner, + EntryPoint = point.EntryPoint, + Version = point.Version, + Language = point.Language, + Extension = point.Extension, + }, + PluginExtensionPointUiPluginExtensionPoint point => new UiPluginExtensionPoint + { + Kind = PluginKind.Ui, + EntryPoint = point.EntryPoint, + Version = point.Version, + RemoteName = point.RemoteName, + RemoteEntry = point.RemoteEntry, + Outlets = MapOutlets(point.Outlets), + }, + _ => null, + }; + } + + private static IEnumerable MapOutlets( + IEnumerable outlets + ) + { + return outlets.Select(MapOutlet); + } + + private static UiPluginExtensionPointOutlet MapOutlet( + InstalledPluginExtensionPointOutletBase outlet + ) + { + return outlet switch + { + InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet topNavigationBarOutlet => + new TopNavigationBarOutlet + { + Type = OutletTypes.TopNavigationBar, + ExposedModule = topNavigationBarOutlet.ExposedModule, + Path = topNavigationBarOutlet.Path, + Label = topNavigationBarOutlet.Label, + Nested = topNavigationBarOutlet.Nested, + ComponentName = topNavigationBarOutlet.ComponentName, + }, + InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet sidePanelOutlet => + new SidePanelOutlet + { + Type = OutletTypes.SidePanel, + ExposedModule = sidePanelOutlet.ExposedModule, + Path = sidePanelOutlet.Path, + Label = sidePanelOutlet.Label, + Nested = sidePanelOutlet.Nested, + ComponentName = sidePanelOutlet.ComponentName, + Icon = sidePanelOutlet.Icon, + }, + InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet filePreviewerOutlet => + new FilePreviewerOutlet + { + Type = OutletTypes.FilePreviewer, + ExposedModule = filePreviewerOutlet.ExposedModule, + Label = filePreviewerOutlet.Label, + ComponentName = filePreviewerOutlet.ComponentName, + Icon = filePreviewerOutlet.Icon, + SupportedFileExtensions = filePreviewerOutlet.SupportedFileExtensions?.ToList(), + }, + _ => new UiPluginExtensionPointOutlet { Type = "unknown" }, + }; } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/InstallPluginAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/InstallPluginAdapter.cs index c224f7ce..dfbac627 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/InstallPluginAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/InstallPluginAdapter.cs @@ -2,8 +2,8 @@ using ScriptBee.Domain.Model.Instance; using ScriptBee.Domain.Model.Plugins; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; -using ScriptBee.Rest.Contracts; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -18,13 +18,9 @@ CancellationToken cancellationToken var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var pluginsApi = RestService.For(client); + var analysisApi = RestService.For(client); - var request = new RestInstallPlugin - { - PluginId = pluginId.Name, - Version = pluginId.Version.ToString(), - }; - await pluginsApi.InstallPlugin(request, cancellationToken); + var request = new InstallPluginCommand(pluginId.Name, pluginId.Version.ToString()); + await analysisApi.PluginsPost(request, cancellationToken); } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LinkInstanceContextAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LinkInstanceContextAdapter.cs index 7c7529dc..fafcd093 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LinkInstanceContextAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LinkInstanceContextAdapter.cs @@ -1,8 +1,8 @@ using Refit; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; -using ScriptBee.Rest.Contracts; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -17,8 +17,8 @@ public async Task Link( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var analysisApi = RestService.For(client); - await contextApi.Link(new RestContextLink { LinkerIds = linkerIds }, cancellationToken); + await analysisApi.Link(new LinkContextCommand(linkerIds.ToList()), cancellationToken); } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LoadInstanceContextAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LoadInstanceContextAdapter.cs index 4911281f..6e75f3ba 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LoadInstanceContextAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/LoadInstanceContextAdapter.cs @@ -2,8 +2,8 @@ using ScriptBee.Domain.Model.File; using ScriptBee.Domain.Model.Instance; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; -using ScriptBee.Rest.Contracts; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -18,21 +18,21 @@ public async Task Load( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var analysisApi = RestService.For(client); - await contextApi.Load( - new RestContextLoad { FilesToLoad = ConvertFilesToLoad(filesToLoad) }, + await analysisApi.Load( + new LoadContextCommand(ConvertFilesToLoad(filesToLoad)), cancellationToken ); } - private static Dictionary> ConvertFilesToLoad( + private static Dictionary> ConvertFilesToLoad( IDictionary> filesToLoad ) { return filesToLoad.ToDictionary( x => x.Key, - y => y.Value.Select(f => f.ToString()).ToList() + y => (ICollection)y.Value.Select(f => f.ToString()).ToList() ); } } diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Rest.csproj b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Rest.csproj index 9d468652..8f9f7346 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Rest.csproj +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/Rest.csproj @@ -5,6 +5,7 @@ + diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/TriggerInstanceAnalysisAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/TriggerInstanceAnalysisAdapter.cs index 2dd17fc1..f52bd27c 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/TriggerInstanceAnalysisAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/TriggerInstanceAnalysisAdapter.cs @@ -4,8 +4,8 @@ using ScriptBee.Domain.Model.Project; using ScriptBee.Domain.Model.ProjectStructure; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; -using ScriptBee.Rest.Contracts; +using ScriptBee.Rest.Api.Generated; +using ScriptBee.Rest.Api.Generated.Contracts; namespace ScriptBee.Rest; @@ -21,14 +21,10 @@ public async Task Trigger( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var contextApi = RestService.For(client); + var analysisApi = RestService.For(client); - var response = await contextApi.TriggerAnalysis( - new RestRunAnalysisCommand - { - ProjectId = instanceInfo.ProjectId.ToString(), - ScriptId = scriptId.ToString(), - }, + var response = await analysisApi.Analyses( + new RunAnalysisCommand(instanceInfo.ProjectId.ToString(), scriptId.ToString()), cancellationToken ); diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/UninstallPluginAdapter.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/UninstallPluginAdapter.cs index f99d44af..04ac138b 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/UninstallPluginAdapter.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/UninstallPluginAdapter.cs @@ -2,7 +2,7 @@ using ScriptBee.Domain.Model.Instance; using ScriptBee.Domain.Model.Plugins; using ScriptBee.Ports.Instance; -using ScriptBee.Rest.Api; +using ScriptBee.Rest.Api.Generated; namespace ScriptBee.Rest; @@ -17,9 +17,9 @@ public async Task Uninstall( var client = httpClientFactory.CreateClient(); client.BaseAddress = new Uri(instanceInfo.Url); - var pluginsApi = RestService.For(client); + var analysisApi = RestService.For(client); - await pluginsApi.UninstallPlugin( + await analysisApi.PluginsDelete( pluginId.Name, pluginId.Version.ToString(), cancellationToken diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Rest/analysis.refitter b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/analysis.refitter new file mode 100644 index 00000000..fb000087 --- /dev/null +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Rest/analysis.refitter @@ -0,0 +1,22 @@ +{ + "openApiPath": "../../../../../docs/public/analysis_swagger.json", + "namespace": "ScriptBee.Rest.Api.Generated", + "contractsNamespace": "ScriptBee.Rest.Api.Generated.Contracts", + "propertyNamingPolicy": "PascalCase", + "naming": { + "useOpenApiTitle": false, + "interfaceName": "AnalysisApi" + }, + "generateContracts": true, + "generateClients": true, + "useCancellationTokens": true, + "immutableRecords": true, + "generateNullableReferenceTypes": true, + "generateNativeRecords": true, + "outputFolder": "./Generated", + "outputFilename": "AnalysisApi.g.cs", + "responseTypeOverride": { + "GenerateClasses": "System.IO.Stream", + "Analyses": "ScriptBee.Rest.Api.Generated.Contracts.RunAnalysisResponse" + } +} diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPoint.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPoint.cs index 10699225..f469c78a 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPoint.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPoint.cs @@ -19,7 +19,9 @@ public static WebInstalledGatewayPluginExtensionPoint Map(PluginExtensionPoint e uiExtensionPoint.Kind, uiExtensionPoint.RemoteName, uiExtensionPoint.RemoteEntry, - uiExtensionPoint.Outlets.Select(WebInstalledGatewayPluginExtensionPointOutlet.Map) + uiExtensionPoint.Outlets.Select( + WebInstalledGatewayPluginExtensionPointOutletBase.Map + ) ), _ => new WebInstalledGatewayPluginExtensionPoint( extensionPoint.Kind, diff --git a/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPointOutlet.cs b/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPointOutlet.cs index 3dd3e291..63752c09 100644 --- a/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPointOutlet.cs +++ b/ScriptBeeWebApp/src/Gateway/Adapters/Web/EndpointDefinitions/Plugins/Contracts/WebInstalledGatewayPluginExtensionPointOutlet.cs @@ -7,21 +7,20 @@ namespace ScriptBee.Web.EndpointDefinitions.Plugins.Contracts; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] [JsonDerivedType( typeof(WebInstalledGatewayPluginTopNavigationBarOutlet), - typeDiscriminator: "top-navigation-bar" + typeDiscriminator: OutletTypes.TopNavigationBar +)] +[JsonDerivedType( + typeof(WebInstalledGatewayPluginSidePanelOutlet), + typeDiscriminator: OutletTypes.SidePanel )] -[JsonDerivedType(typeof(WebInstalledGatewayPluginSidePanelOutlet), typeDiscriminator: "side-panel")] [JsonDerivedType( typeof(WebInstalledGatewayPluginFilePreviewerOutlet), - typeDiscriminator: "file-previewer" + typeDiscriminator: OutletTypes.FilePreviewer )] [Description("Base class for outlets of an installed gateway plugin extension point.")] public abstract record WebInstalledGatewayPluginExtensionPointOutletBase( [property: JsonIgnore] string Type -); - -[Description("Represents an outlet of an installed gateway plugin extension point.")] -public record WebInstalledGatewayPluginExtensionPointOutlet(string Type) - : WebInstalledGatewayPluginExtensionPointOutletBase(Type) +) { public static WebInstalledGatewayPluginExtensionPointOutletBase Map( UiPluginExtensionPointOutlet outlet diff --git a/ScriptBeeWebApp/test/Analysis/Adapters/Analysis.Web.Tests/EndpointDefinitions/Plugins/GetInstalledPluginsEndpointTest.cs b/ScriptBeeWebApp/test/Analysis/Adapters/Analysis.Web.Tests/EndpointDefinitions/Plugins/GetInstalledPluginsEndpointTest.cs index 49e71056..68fe6875 100644 --- a/ScriptBeeWebApp/test/Analysis/Adapters/Analysis.Web.Tests/EndpointDefinitions/Plugins/GetInstalledPluginsEndpointTest.cs +++ b/ScriptBeeWebApp/test/Analysis/Adapters/Analysis.Web.Tests/EndpointDefinitions/Plugins/GetInstalledPluginsEndpointTest.cs @@ -241,7 +241,7 @@ public async Task ShouldReturnUiPlugin() { new TopNavigationBarOutlet { - Type = "top-navigation-bar", + Type = OutletTypes.TopNavigationBar, ExposedModule = "./routes", Path = "/my-plugin", Label = "Flights", @@ -281,7 +281,7 @@ public async Task ShouldReturnUiPlugin() extensionPoint.GetProperty("remoteEntry").GetString().ShouldBe("remote-entry"); var outlets = extensionPoint.GetProperty("outlets").EnumerateArray(); var outlet = outlets.Single(); - outlet.GetProperty("type").GetString().ShouldBe("top-navigation-bar"); + outlet.GetProperty("type").GetString().ShouldBe(OutletTypes.TopNavigationBar); } private static Plugin CreatePlugin(PluginExtensionPoint extensionPoint) diff --git a/ScriptBeeWebApp/test/Common/Tests.Common/Plugins/TestPlugin.cs b/ScriptBeeWebApp/test/Common/Tests.Common/Plugins/TestPlugin.cs index c3beba48..a7930a38 100644 --- a/ScriptBeeWebApp/test/Common/Tests.Common/Plugins/TestPlugin.cs +++ b/ScriptBeeWebApp/test/Common/Tests.Common/Plugins/TestPlugin.cs @@ -31,7 +31,7 @@ public record TestUiPlugin(PluginId Id, string FolderPath = "path") { new TopNavigationBarOutlet { - Type = "top-navigation-bar", + Type = OutletTypes.TopNavigationBar, ExposedModule = "./routes", Path = "/my-plugin", Label = "Flights", @@ -40,7 +40,7 @@ public record TestUiPlugin(PluginId Id, string FolderPath = "path") }, new SidePanelOutlet { - Type = "side-panel", + Type = OutletTypes.SidePanel, ExposedModule = "./Component", Path = "/my-plugin", Label = "My Plugin", @@ -50,7 +50,7 @@ public record TestUiPlugin(PluginId Id, string FolderPath = "path") }, new FilePreviewerOutlet { - Type = "file-previewer", + Type = OutletTypes.FilePreviewer, ExposedModule = "./Component", Label = "My Plugin", ComponentName = null, diff --git a/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/Converters/JsonStringEnumMemberConverterFactoryTests.cs b/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/Converters/JsonStringEnumMemberConverterFactoryTests.cs new file mode 100644 index 00000000..7c1d9a0a --- /dev/null +++ b/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/Converters/JsonStringEnumMemberConverterFactoryTests.cs @@ -0,0 +1,95 @@ +using System.Runtime.Serialization; +using System.Text.Json; +using ScriptBee.Rest.Converters; + +namespace ScriptBee.Rest.Tests.Converters; + +public class JsonStringEnumMemberConverterFactoryTest +{ + private static readonly JsonSerializerOptions Options = new() + { + Converters = { new JsonStringEnumMemberConverterFactory() }, + }; + + [Fact] + public void ShouldDeserializeUsingEnumMember() + { + var value = JsonSerializer.Deserialize( + """ + "top-navigation-bar" + """, + Options + ); + + value.ShouldBe(TestEnum.TopNavigationBar); + } + + [Fact] + public void ShouldDeserializeSecondEnumMember() + { + var value = JsonSerializer.Deserialize( + """ + "side-panel" + """, + Options + ); + + value.ShouldBe(TestEnum.SidePanel); + } + + [Fact] + public void ShouldDeserializeUsingNameWhenEnumMemberIsMissing() + { + var value = JsonSerializer.Deserialize(@"""NoAttribute""", Options); + + value.ShouldBe(TestEnum.NoAttribute); + } + + [Fact] + public void ShouldSerializeUsingEnumMember() + { + var json = JsonSerializer.Serialize(TestEnum.TopNavigationBar, Options); + + json.ShouldBe( + """ + "top-navigation-bar" + """ + ); + } + + [Fact] + public void ShouldSerializeUsingNameWhenEnumMemberIsMissing() + { + var json = JsonSerializer.Serialize(TestEnum.NoAttribute, Options); + + json.ShouldBe( + """ + "NoAttribute" + """ + ); + } + + [Fact] + public void ShouldThrowForUnknownValue() + { + Should.Throw(() => + JsonSerializer.Deserialize( + """ + "does-not-exist" + """, + Options + ) + ); + } +} + +public enum TestEnum +{ + [EnumMember(Value = "top-navigation-bar")] + TopNavigationBar, + + [EnumMember(Value = "side-panel")] + SidePanel, + + NoAttribute, +} diff --git a/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/GetPluginsAdapterTest.cs b/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/GetPluginsAdapterTest.cs index 059e6b70..40bd7fa3 100644 --- a/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/GetPluginsAdapterTest.cs +++ b/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/GetPluginsAdapterTest.cs @@ -1,3 +1,4 @@ +using Refit; using ScriptBee.Domain.Model.Instance; using ScriptBee.Domain.Model.Plugins; using ScriptBee.Domain.Model.Plugins.Manifest; @@ -243,11 +244,11 @@ public async Task ShouldReturnUiPlugin() pluginExtensionPoint.RemoteName.ShouldBe("scriptbee-ui-plugin-example"); pluginExtensionPoint.RemoteEntry.ShouldBe("remote-entry"); var outlet = pluginExtensionPoint.Outlets.Single(); - outlet.Type.ShouldBe("top-navigation-bar"); + outlet.Type.ShouldBe(OutletTypes.TopNavigationBar); } [Fact] - public async Task GivenUnknownKind_ShouldReturnPluginWithoutExtensionPoints() + public async Task GivenUnknownKind_ShouldThrowException() { MockGetPlugins( """ @@ -259,20 +260,18 @@ public async Task GivenUnknownKind_ShouldReturnPluginWithoutExtensionPoints() """ ); - var response = await _getPluginsAdapter.GetLoadedPlugins( - new InstanceInfo( - new InstanceId(Guid.Empty), - ProjectId.FromValue("id"), - _server.Urls[0], - DateTimeOffset.Now, - AnalysisInstanceStatus.NotFound - ), - TestContext.Current.CancellationToken + await Assert.ThrowsAsync(() => + _getPluginsAdapter.GetLoadedPlugins( + new InstanceInfo( + new InstanceId(Guid.Empty), + ProjectId.FromValue("id"), + _server.Urls[0], + DateTimeOffset.Now, + AnalysisInstanceStatus.NotFound + ), + TestContext.Current.CancellationToken + ) ); - - var plugin = response.Single(); - AssertPluginProperties(plugin); - plugin.Manifest.ExtensionPoints.ShouldBeEmpty(); } private void MockGetPlugins(string extensionPoint) diff --git a/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/RestPluginExtensionPointTests.cs b/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/RestPluginExtensionPointTests.cs deleted file mode 100644 index 00fb8a22..00000000 --- a/ScriptBeeWebApp/test/Gateway/Adapters/Rest.Tests/RestPluginExtensionPointTests.cs +++ /dev/null @@ -1,114 +0,0 @@ -using ScriptBee.Domain.Model.Plugins.Manifest; -using ScriptBee.Rest.Contracts; - -namespace ScriptBee.Rest.Tests; - -public class RestPluginExtensionPointTests -{ - [Fact] - public void Map_Should_Map_TopNavigationBarOutlet() - { - var rest = new RestPluginExtensionPoint - { - Kind = PluginKind.Ui, - EntryPoint = string.Empty, - Version = string.Empty, - RemoteName = "name", - RemoteEntry = "entry", - Outlets = new List - { - new RestUiPluginExtensionPointOutlet - { - Type = "top-navigation-bar", - ExposedModule = "./routes", - Path = "/my-plugin", - Label = "Flights", - Nested = true, - ComponentName = null, - }, - }, - }; - - var mapped = rest.Map(); - - var ui = mapped as UiPluginExtensionPoint; - ui.ShouldNotBeNull(); - var outlet = ui.Outlets.Single(); - outlet.ShouldBeOfType(); - var top = (TopNavigationBarOutlet)outlet; - top.ExposedModule.ShouldBe("./routes"); - top.Path.ShouldBe("/my-plugin"); - top.Label.ShouldBe("Flights"); - top.Nested.ShouldBe(true); - } - - [Fact] - public void Map_Should_Map_SidePanelOutlet() - { - var rest = new RestPluginExtensionPoint - { - Kind = PluginKind.Ui, - EntryPoint = string.Empty, - Version = string.Empty, - RemoteName = "name", - RemoteEntry = "entry", - Outlets = new List - { - new RestUiPluginExtensionPointOutlet - { - Type = "side-panel", - ExposedModule = "./Component", - Path = "/my-plugin", - Label = "My Plugin", - Nested = null, - ComponentName = null, - Icon = "favorite", - }, - }, - }; - - var mapped = rest.Map(); - - var ui = mapped as UiPluginExtensionPoint; - ui.ShouldNotBeNull(); - var outlet = ui.Outlets.Single(); - outlet.ShouldBeOfType(); - var side = (SidePanelOutlet)outlet; - side.Icon.ShouldBe("favorite"); - } - - [Fact] - public void Map_Should_Map_FilePreviewerOutlet() - { - var rest = new RestPluginExtensionPoint - { - Kind = PluginKind.Ui, - EntryPoint = string.Empty, - Version = string.Empty, - RemoteName = "name", - RemoteEntry = "entry", - Outlets = new List - { - new() - { - Type = "file-previewer", - ExposedModule = "./Component", - Label = "My Plugin", - ComponentName = null, - Icon = null, - SupportedFileExtensions = ["json"], - }, - }, - }; - - var mapped = rest.Map(); - - var ui = mapped as UiPluginExtensionPoint; - ui.ShouldNotBeNull(); - var outlet = ui.Outlets.Single(); - outlet.ShouldBeOfType(); - var file = (FilePreviewerOutlet)outlet; - file.SupportedFileExtensions.ShouldNotBeNull(); - file.SupportedFileExtensions.ShouldContain("json"); - } -} diff --git a/ScriptBeeWebApp/test/Plugins/Plugins.Tests/Manifest/PluginManifestYamlParsingTests.cs b/ScriptBeeWebApp/test/Plugins/Plugins.Tests/Manifest/PluginManifestYamlParsingTests.cs index 691cbd37..535e5715 100644 --- a/ScriptBeeWebApp/test/Plugins/Plugins.Tests/Manifest/PluginManifestYamlParsingTests.cs +++ b/ScriptBeeWebApp/test/Plugins/Plugins.Tests/Manifest/PluginManifestYamlParsingTests.cs @@ -124,7 +124,7 @@ public void GivenManifestContent_ThenUiPluginManifestIsConstructed(string filePa Assert.Equal("http://localhost:8080/remoteEntry.js", extensionPoint.RemoteEntry); Assert.NotNull(extensionPoint.Outlets); var outlet = Assert.Single(extensionPoint.Outlets); - Assert.Equal("top-navigation-bar", outlet.Type); + Assert.Equal(OutletTypes.TopNavigationBar, outlet.Type); } [Theory] diff --git a/docs/public/analysis_swagger.json b/docs/public/analysis_swagger.json index 16fcdbbf..a1d44d42 100644 --- a/docs/public/analysis_swagger.json +++ b/docs/public/analysis_swagger.json @@ -13,9 +13,12 @@ "paths": { "/api/plugins": { "get": { - "tags": ["Plugins"], + "tags": [ + "Plugins" + ], "summary": "Get installed plugins", "description": "Retrieves a list of all plugins currently installed in the analysis service.", + "operationId": "PluginsGet", "responses": { "200": { "description": "OK", @@ -30,9 +33,12 @@ } }, "post": { - "tags": ["Plugins"], + "tags": [ + "Plugins" + ], "summary": "Install a plugin", "description": "Installs a specific plugin version into the analysis service.", + "operationId": "PluginsPost", "requestBody": { "content": { "application/json": { @@ -72,9 +78,12 @@ }, "/api/plugins/{pluginId}": { "delete": { - "tags": ["Plugins"], + "tags": [ + "Plugins" + ], "summary": "Uninstall a plugin", "description": "Uninstalls a specific plugin version from the analysis service.", + "operationId": "PluginsDelete", "parameters": [ { "name": "pluginId", @@ -102,9 +111,12 @@ }, "/api/context/clear": { "post": { - "tags": ["Context"], + "tags": [ + "Context" + ], "summary": "Clear analysis context", "description": "Clears all data from the current analysis context.", + "operationId": "Clear", "responses": { "204": { "description": "No Content" @@ -114,9 +126,12 @@ }, "/api/context/generate-classes": { "post": { - "tags": ["Context"], + "tags": [ + "Context" + ], "summary": "Generate classes for analysis context", "description": "Generates script classes based on the current data context and returns them as a stream.", + "operationId": "GenerateClasses", "requestBody": { "content": { "application/json": { @@ -136,9 +151,12 @@ }, "/api/context": { "get": { - "tags": ["Context"], + "tags": [ + "Context" + ], "summary": "Get analysis context", "description": "Retrieves the current data context from the analysis service.", + "operationId": "Context", "responses": { "200": { "description": "OK", @@ -155,15 +173,20 @@ }, "/api/context/graph-nodes": { "get": { - "tags": ["Context", "Graph"], + "tags": [ + "Context", + "Graph" + ], "summary": "Search context nodes", "description": "Searches for context nodes based on a query string.", + "operationId": "GraphNodes", "parameters": [ { "name": "query", "in": "query", "schema": { - "type": "string" + "type": "string", + "default": "" } }, { @@ -171,7 +194,10 @@ "in": "query", "schema": { "pattern": "^-?(?:0|[1-9]\\d*)$", - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "format": "int32", "default": 0 } @@ -181,7 +207,10 @@ "in": "query", "schema": { "pattern": "^-?(?:0|[1-9]\\d*)$", - "type": ["integer", "string"], + "type": [ + "integer", + "string" + ], "format": "int32", "default": 10 } @@ -203,9 +232,13 @@ }, "/api/context/graph-nodes/{nodeId}/neighbors": { "get": { - "tags": ["Context", "Graph"], + "tags": [ + "Context", + "Graph" + ], "summary": "Get node neighbors", "description": "Retrieves the immediate neighbors and edges for a specific context node.", + "operationId": "Neighbors", "parameters": [ { "name": "nodeId", @@ -232,9 +265,12 @@ }, "/api/context/link": { "post": { - "tags": ["Context"], + "tags": [ + "Context" + ], "summary": "Link analysis context", "description": "Links the current analysis context using the provided linkers.", + "operationId": "Link", "requestBody": { "content": { "application/json": { @@ -264,9 +300,12 @@ }, "/api/context/load": { "post": { - "tags": ["Context"], + "tags": [ + "Context" + ], "summary": "Load data into analysis context", "description": "Loads data from files into the current analysis context using the provided loaders.", + "operationId": "Load", "requestBody": { "content": { "application/json": { @@ -296,9 +335,12 @@ }, "/api/analyses": { "post": { - "tags": ["Analysis"], + "tags": [ + "Analysis" + ], "summary": "Run analysis", "description": "Starts the execution of an analysis script on the analysis service.", + "operationId": "Analyses", "requestBody": { "content": { "application/json": { @@ -337,7 +379,11 @@ "components": { "schemas": { "ContextGraphEdge": { - "required": ["source", "target", "label"], + "required": [ + "source", + "target", + "label" + ], "type": "object", "properties": { "source": { @@ -352,7 +398,13 @@ } }, "ContextGraphNode": { - "required": ["id", "label", "type", "loader", "properties"], + "required": [ + "id", + "label", + "type", + "loader", + "properties" + ], "type": "object", "properties": { "id": { @@ -365,7 +417,10 @@ "type": "string" }, "loader": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "properties": { "type": "object" @@ -373,7 +428,10 @@ } }, "ContextGraphResponse": { - "required": ["nodes", "edges"], + "required": [ + "nodes", + "edges" + ], "type": "object", "properties": { "nodes": { @@ -391,7 +449,10 @@ } }, "ContextSlice": { - "required": ["model", "pluginIds"], + "required": [ + "model", + "pluginIds" + ], "type": "object", "properties": { "model": { @@ -406,22 +467,32 @@ } }, "GenerateClassesRequest": { - "required": ["languages"], + "required": [ + "languages" + ], "type": "object", "properties": { "languages": { - "type": ["null", "array"], + "type": [ + "null", + "array" + ], "items": { "type": "string" } }, "transferFormat": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] } } }, "GetContextResponse": { - "required": ["data"], + "required": [ + "data" + ], "type": "object", "properties": { "data": { @@ -433,7 +504,9 @@ } }, "GetInstalledPluginsResponse": { - "required": ["data"], + "required": [ + "data" + ], "type": "object", "properties": { "data": { @@ -448,21 +521,37 @@ "type": "object", "properties": { "type": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "title": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "status": { "pattern": "^-?(?:0|[1-9]\\d*)$", - "type": ["null", "integer", "string"], + "type": [ + "null", + "integer", + "string" + ], "format": "int32" }, "detail": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "instance": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "errors": { "type": "object", @@ -476,7 +565,12 @@ } }, "InstalledPlugin": { - "required": ["folderPath", "id", "version", "manifest"], + "required": [ + "folderPath", + "id", + "version", + "manifest" + ], "type": "object", "properties": { "folderPath": { @@ -493,8 +587,167 @@ } } }, + "InstalledPluginExtensionPointOutletBase": { + "required": [ + "type" + ], + "type": "object", + "anyOf": [ + { + "$ref": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet" + }, + { + "$ref": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet" + }, + { + "$ref": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet" + } + ], + "description": "Base class for outlets of a plugin extension point.", + "discriminator": { + "propertyName": "type", + "mapping": { + "top-navigation-bar": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet", + "side-panel": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet", + "file-previewer": "#/components/schemas/InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet" + } + } + }, + "InstalledPluginExtensionPointOutletBaseInstalledPluginFilePreviewerOutlet": { + "required": [ + "exposedModule", + "label", + "componentName", + "icon", + "supportedFileExtensions" + ], + "properties": { + "type": { + "enum": [ + "file-previewer" + ], + "type": "string" + }, + "exposedModule": { + "type": "string" + }, + "label": { + "type": "string" + }, + "componentName": { + "type": [ + "null", + "string" + ] + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "supportedFileExtensions": { + "type": [ + "null", + "array" + ], + "items": { + "type": "string" + } + } + }, + "description": "Represents a component for file previewer of output results." + }, + "InstalledPluginExtensionPointOutletBaseInstalledPluginSidePanelOutlet": { + "required": [ + "exposedModule", + "label", + "path", + "nested", + "componentName", + "icon" + ], + "properties": { + "type": { + "enum": [ + "side-panel" + ], + "type": "string" + }, + "exposedModule": { + "type": "string" + }, + "label": { + "type": "string" + }, + "path": { + "type": "string" + }, + "nested": { + "type": [ + "null", + "boolean" + ] + }, + "componentName": { + "type": [ + "null", + "string" + ] + }, + "icon": { + "type": "string" + } + }, + "description": "Represents an element from the Side Hamburger Panel with route." + }, + "InstalledPluginExtensionPointOutletBaseInstalledPluginTopNavigationBarOutlet": { + "required": [ + "exposedModule", + "label", + "path", + "nested", + "componentName" + ], + "properties": { + "type": { + "enum": [ + "top-navigation-bar" + ], + "type": "string" + }, + "exposedModule": { + "type": "string" + }, + "label": { + "type": "string" + }, + "path": { + "type": "string" + }, + "nested": { + "type": [ + "null", + "boolean" + ] + }, + "componentName": { + "type": [ + "null", + "string" + ] + } + }, + "description": "Represents an element from the Top Navigation Bar with route." + }, "InstalledPluginManifest": { - "required": ["apiVersion", "name", "description", "author", "extensionPoints"], + "required": [ + "apiVersion", + "name", + "description", + "author", + "extensionPoints" + ], "type": "object", "properties": { "apiVersion": { @@ -504,18 +757,30 @@ "type": "string" }, "description": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "author": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "extensionPoints": { - "type": "array" + "type": "array", + "items": { + "$ref": "#/components/schemas/PluginExtensionPoint" + } } } }, "InstallPluginCommand": { - "required": ["pluginId", "version"], + "required": [ + "pluginId", + "version" + ], "type": "object", "properties": { "pluginId": { @@ -527,7 +792,9 @@ } }, "LinkContextCommand": { - "required": ["linkerIds"], + "required": [ + "linkerIds" + ], "type": "object", "properties": { "linkerIds": { @@ -539,7 +806,9 @@ } }, "LoadContextCommand": { - "required": ["filesToLoad"], + "required": [ + "filesToLoad" + ], "type": "object", "properties": { "filesToLoad": { @@ -553,30 +822,269 @@ } } }, + "PluginExtensionPoint": { + "required": [ + "kind" + ], + "type": "object", + "anyOf": [ + { + "$ref": "#/components/schemas/PluginExtensionPointNestedPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointLoaderPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointLinkerPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointScriptGeneratorPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointScriptRunnerPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointHelperFunctionsPluginExtensionPoint" + }, + { + "$ref": "#/components/schemas/PluginExtensionPointUiPluginExtensionPoint" + } + ], + "description": "Base class for plugin extension points", + "discriminator": { + "propertyName": "kind", + "mapping": { + "Plugin": "#/components/schemas/PluginExtensionPointNestedPluginExtensionPoint", + "Loader": "#/components/schemas/PluginExtensionPointLoaderPluginExtensionPoint", + "Linker": "#/components/schemas/PluginExtensionPointLinkerPluginExtensionPoint", + "ScriptGenerator": "#/components/schemas/PluginExtensionPointScriptGeneratorPluginExtensionPoint", + "ScriptRunner": "#/components/schemas/PluginExtensionPointScriptRunnerPluginExtensionPoint", + "HelperFunctions": "#/components/schemas/PluginExtensionPointHelperFunctionsPluginExtensionPoint", + "UI": "#/components/schemas/PluginExtensionPointUiPluginExtensionPoint" + } + } + }, + "PluginExtensionPointHelperFunctionsPluginExtensionPoint": { + "required": [ + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "HelperFunctions" + ], + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a helper functions plugin extension point." + }, + "PluginExtensionPointLinkerPluginExtensionPoint": { + "required": [ + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "Linker" + ], + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a linker plugin extension point." + }, + "PluginExtensionPointLoaderPluginExtensionPoint": { + "required": [ + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "Loader" + ], + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a loader plugin extension point." + }, + "PluginExtensionPointNestedPluginExtensionPoint": { + "required": [ + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "Plugin" + ], + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a plugin from a bundle." + }, + "PluginExtensionPointScriptGeneratorPluginExtensionPoint": { + "required": [ + "language", + "extension", + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "ScriptGenerator" + ], + "type": "string" + }, + "language": { + "type": "string" + }, + "extension": { + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a script generator plugin extension point." + }, + "PluginExtensionPointScriptRunnerPluginExtensionPoint": { + "required": [ + "language", + "extension", + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "ScriptRunner" + ], + "type": "string" + }, + "language": { + "type": "string" + }, + "extension": { + "type": "string" + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a script runner plugin extension point." + }, + "PluginExtensionPointUiPluginExtensionPoint": { + "required": [ + "remoteName", + "remoteEntry", + "outlets", + "entryPoint", + "version" + ], + "properties": { + "kind": { + "enum": [ + "UI" + ], + "type": "string" + }, + "remoteName": { + "type": "string" + }, + "remoteEntry": { + "type": "string" + }, + "outlets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InstalledPluginExtensionPointOutletBase" + } + }, + "entryPoint": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "description": "Represents a UI plugin extension point." + }, "ProblemDetails": { "type": "object", "properties": { "type": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "title": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "status": { "pattern": "^-?(?:0|[1-9]\\d*)$", - "type": ["null", "integer", "string"], + "type": [ + "null", + "integer", + "string" + ], "format": "int32" }, "detail": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] }, "instance": { - "type": ["null", "string"] + "type": [ + "null", + "string" + ] } } }, "RunAnalysisCommand": { - "required": ["projectId", "scriptId"], + "required": [ + "projectId", + "scriptId" + ], "type": "object", "properties": { "projectId": { @@ -589,7 +1097,13 @@ "description": "Command used to run an analysis script on the analysis service." }, "RunAnalysisResponse": { - "required": ["id", "projectId", "scriptId", "status", "creationDate"], + "required": [ + "id", + "projectId", + "scriptId", + "status", + "creationDate" + ], "type": "object", "properties": { "id": {