diff --git a/rubberduckvba.Server/Api/Admin/WebhookController.cs b/rubberduckvba.Server/Api/Admin/WebhookController.cs index 3015ceb..8f99aab 100644 --- a/rubberduckvba.Server/Api/Admin/WebhookController.cs +++ b/rubberduckvba.Server/Api/Admin/WebhookController.cs @@ -22,36 +22,35 @@ public WebhookController( [Authorize("webhook")] [HttpPost("webhook/github")] - public async Task GitHub([FromBody] dynamic body) - { - //var reader = new StreamReader(Request.Body); - //var json = await reader.ReadToEndAsync(); - string json = body.ToString(); - - var payload = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) - ?? throw new InvalidOperationException("Could not deserialize payload"); - var eventType = _validator.Validate(payload, json, Request.Headers, out var content, out var gitref); - - if (eventType == WebhookPayloadType.Push) - { - var jobId = _hangfire.UpdateXmldocContent(); - var message = $"Webhook push event was accepted. Tag '{gitref?.Name}' associated to the payload will be processed by JobId '{jobId}'."; - - Logger.LogInformation(message); - return Ok(message); - } - else if (eventType == WebhookPayloadType.Ping) - { - Logger.LogInformation("Webhook ping event was accepted; nothing to process."); - return Ok(); - } - else if (eventType == WebhookPayloadType.Greeting) + public async Task GitHub([FromBody] dynamic body) => + GuardInternalAction(() => { - Logger.LogInformation("Webhook push event was accepted; nothing to process. {content}", content); - return string.IsNullOrWhiteSpace(content) ? NoContent() : Ok(content); - } - - // reject the payload - return BadRequest(); - } + string json = body.ToString(); + + var payload = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) + ?? throw new InvalidOperationException("Could not deserialize payload"); + var eventType = _validator.Validate(payload, json, Request.Headers, out var content, out var gitref); + + if (eventType == WebhookPayloadType.Push) + { + var jobId = _hangfire.UpdateXmldocContent(); + var message = $"Webhook push event was accepted. Tag '{gitref?.Name}' associated to the payload will be processed by JobId '{jobId}'."; + + Logger.LogInformation(message); + return Ok(message); + } + else if (eventType == WebhookPayloadType.Ping) + { + Logger.LogInformation("Webhook ping event was accepted; nothing to process."); + return Ok(); + } + else if (eventType == WebhookPayloadType.Greeting) + { + Logger.LogInformation("Webhook push event was accepted; nothing to process. {content}", content); + return string.IsNullOrWhiteSpace(content) ? NoContent() : Ok(content); + } + + // reject the payload + return BadRequest(); + }); } diff --git a/rubberduckvba.Server/Api/Auth/AuthController.cs b/rubberduckvba.Server/Api/Auth/AuthController.cs index 3e76251..05a8818 100644 --- a/rubberduckvba.Server/Api/Auth/AuthController.cs +++ b/rubberduckvba.Server/Api/Auth/AuthController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Octokit; using Octokit.Internal; @@ -23,91 +24,113 @@ public record class SignInViewModel } [ApiController] -public class AuthController(IOptions configuration, IOptions api, ILogger logger) : ControllerBase +[AllowAnonymous] +public class AuthController : RubberduckApiController { + private readonly IOptions configuration; + + public AuthController(IOptions configuration, IOptions api, ILogger logger) + : base(logger) + { + this.configuration = configuration; + } + [HttpGet("auth")] + [AllowAnonymous] public IActionResult Index() { - var claims = HttpContext.User.Claims.ToDictionary(claim => claim.Type, claim => claim.Value); - var hasName = claims.TryGetValue(ClaimTypes.Name, out var name); - var hasRole = claims.TryGetValue(ClaimTypes.Role, out var role); - - if (hasName && hasRole) + return GuardInternalAction(() => { - if (string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(role)) + var claims = HttpContext.User.Claims.ToDictionary(claim => claim.Type, claim => claim.Value); + var hasName = claims.TryGetValue(ClaimTypes.Name, out var name); + var hasRole = claims.TryGetValue(ClaimTypes.Role, out var role); + + if (hasName && hasRole) { - return BadRequest(); + if (string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(role)) + { + return BadRequest(); + } + + var isAuthenticated = HttpContext.User.Identity?.IsAuthenticated ?? false; + var model = new UserViewModel + { + Name = name, + IsAuthenticated = isAuthenticated, + IsAdmin = role == configuration.Value.OwnerOrg + }; + + return Ok(model); } - - var isAuthenticated = HttpContext.User.Identity?.IsAuthenticated ?? false; - var model = new UserViewModel + else { - Name = name, - IsAuthenticated = isAuthenticated, - IsAdmin = role == configuration.Value.OwnerOrg - }; - - return Ok(model); - } - else - { - return Ok(UserViewModel.Anonymous); - } + return Ok(UserViewModel.Anonymous); + } + }); } [HttpPost("auth/signin")] + [AllowAnonymous] public IActionResult SessionSignIn(SignInViewModel vm) { - if (User.Identity?.IsAuthenticated ?? false) + return GuardInternalAction(() => { - logger.LogInformation("Signin was requested, but user is already authenticated. Redirecting to home page..."); - return Redirect("/"); - } + if (User.Identity?.IsAuthenticated ?? false) + { + Logger.LogInformation("Signin was requested, but user is already authenticated. Redirecting to home page..."); + return Redirect("/"); + } - var clientId = configuration.Value.ClientId; - var agent = configuration.Value.UserAgent; + var clientId = configuration.Value.ClientId; + var agent = configuration.Value.UserAgent; - var github = new GitHubClient(new ProductHeaderValue(agent)); - var request = new OauthLoginRequest(clientId) - { - AllowSignup = false, - Scopes = { "read:user", "read:org" }, - State = vm.State - }; - - logger.LogInformation("Requesting OAuth app GitHub login url..."); - var url = github.Oauth.GetGitHubLoginUrl(request); - if (url is null) - { - logger.LogInformation("OAuth login was cancelled by the user or did not return a url."); - return Forbid(); - } + var github = new GitHubClient(new ProductHeaderValue(agent)); + var request = new OauthLoginRequest(clientId) + { + AllowSignup = false, + Scopes = { "read:user", "read:org" }, + State = vm.State + }; - logger.LogInformation("Returning the login url for the client to redirect. State: {xsrf}", vm.State); - return Ok(url.ToString()); + Logger.LogInformation("Requesting OAuth app GitHub login url..."); + var url = github.Oauth.GetGitHubLoginUrl(request); + if (url is null) + { + Logger.LogInformation("OAuth login was cancelled by the user or did not return a url."); + return Forbid(); + } + + Logger.LogInformation("Returning the login url for the client to redirect. State: {xsrf}", vm.State); + return Ok(url.ToString()); + }); } [HttpPost("auth/github")] - public async Task OnGitHubCallback(SignInViewModel vm) + [AllowAnonymous] + public IActionResult OnGitHubCallback(SignInViewModel vm) { - logger.LogInformation("OAuth token was received. State: {state}", vm.State); - var clientId = configuration.Value.ClientId; - var clientSecret = configuration.Value.ClientSecret; - var agent = configuration.Value.UserAgent; + return GuardInternalAction(() => + { + Logger.LogInformation("OAuth token was received. State: {state}", vm.State); + var clientId = configuration.Value.ClientId; + var clientSecret = configuration.Value.ClientSecret; + var agent = configuration.Value.UserAgent; - var github = new GitHubClient(new ProductHeaderValue(agent)); + var github = new GitHubClient(new ProductHeaderValue(agent)); - var request = new OauthTokenRequest(clientId, clientSecret, vm.Code); - var token = await github.Oauth.CreateAccessToken(request); - if (token is null) - { - logger.LogWarning("OAuth access token was not created."); - return Unauthorized(); - } + var request = new OauthTokenRequest(clientId, clientSecret, vm.Code); + var token = github.Oauth.CreateAccessToken(request).GetAwaiter().GetResult(); + if (token is null) + { + Logger.LogWarning("OAuth access token was not created."); + return Unauthorized(); + } + + Logger.LogInformation("OAuth access token was created. Authorizing..."); + var authorizedToken = AuthorizeAsync(token.AccessToken).GetAwaiter().GetResult(); - logger.LogInformation("OAuth access token was created. Authorizing..."); - var authorizedToken = await AuthorizeAsync(token.AccessToken); - return authorizedToken is null ? Unauthorized() : Ok(vm with { Token = authorizedToken }); + return authorizedToken is null ? Unauthorized() : Ok(vm with { Token = authorizedToken }); + }); } private async Task AuthorizeAsync(string token) @@ -119,13 +142,13 @@ public async Task OnGitHubCallback(SignInViewModel vm) var githubUser = await github.User.Current(); if (githubUser.Suspended) { - logger.LogWarning("User {name} with login '{login}' ({url}) is a suspended GitHub account and will not be authorized.", githubUser.Name, githubUser.Login, githubUser.Url); + Logger.LogWarning("User login '{login}' ({name}) is a suspended GitHub account and will not be authorized.", githubUser.Login, githubUser.Name); return default; } var identity = new ClaimsIdentity("github", ClaimTypes.Name, ClaimTypes.Role); identity.AddClaim(new Claim(ClaimTypes.Name, githubUser.Login)); - logger.LogInformation("Creating claims identity for GitHub login '{login}'...", githubUser.Login); + Logger.LogInformation("Creating claims identity for GitHub login '{login}'...", githubUser.Login); var orgs = await github.Organization.GetAllForUser(githubUser.Login); var rdOrg = orgs.SingleOrDefault(org => org.Id == configuration.Value.RubberduckOrgId); @@ -135,7 +158,7 @@ public async Task OnGitHubCallback(SignInViewModel vm) identity.AddClaim(new Claim(ClaimTypes.Role, configuration.Value.OwnerOrg)); identity.AddClaim(new Claim(ClaimTypes.Authentication, token)); identity.AddClaim(new Claim("access_token", token)); - logger.LogDebug("GitHub Organization claims were granted. Creating claims principal..."); + Logger.LogDebug("GitHub Organization claims were granted. Creating claims principal..."); var principal = new ClaimsPrincipal(identity); var roles = string.Join(",", identity.Claims.Where(claim => claim.Type == ClaimTypes.Role).Select(claim => claim.Value)); @@ -143,19 +166,19 @@ public async Task OnGitHubCallback(SignInViewModel vm) HttpContext.User = principal; Thread.CurrentPrincipal = HttpContext.User; - logger.LogInformation("GitHub user with login {login} has signed in with role authorizations '{role}'.", githubUser.Login, configuration.Value.OwnerOrg); + Logger.LogInformation("GitHub user with login {login} has signed in with role authorizations '{role}'.", githubUser.Login, configuration.Value.OwnerOrg); return token; } else { - logger.LogWarning("User {name} ({email}) with login '{login}' is not a member of organization ID {org} and will not be authorized.", githubUser.Name, githubUser.Email, githubUser.Login, configuration.Value.RubberduckOrgId); + Logger.LogWarning("User {name} ({email}) with login '{login}' is not a member of organization ID {org} and will not be authorized.", githubUser.Name, githubUser.Email, githubUser.Login, configuration.Value.RubberduckOrgId); return default; } } catch (Exception) { // just ignore: configuration needs the org (prod) client app id to avoid throwing this exception - logger.LogWarning("An exception was thrown. Verify GitHub:ClientId and GitHub:ClientSecret configuration; authorization fails."); + Logger.LogWarning("An exception was thrown. Verify GitHub:ClientId and GitHub:ClientSecret configuration; authorization fails."); return default; } } diff --git a/rubberduckvba.Server/Api/Indenter/IndenterController.cs b/rubberduckvba.Server/Api/Indenter/IndenterController.cs new file mode 100644 index 0000000..80f59b4 --- /dev/null +++ b/rubberduckvba.Server/Api/Indenter/IndenterController.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using RubberduckServices; + +namespace rubberduckvba.Server.Api.Indenter; + +[AllowAnonymous] +public class IndenterController : RubberduckApiController +{ + private readonly IIndenterService service; + + public IndenterController(IIndenterService service, ILogger logger) + : base(logger) + { + this.service = service; + } + + [HttpGet("indenter/version")] + [AllowAnonymous] + public IActionResult Version() => + GuardInternalAction(() => Ok(service.IndenterVersion())); + + [HttpGet("indenter/defaults")] + [AllowAnonymous] + public IActionResult DefaultSettings() => + GuardInternalAction(() => + { + var result = new IndenterViewModel + { + IndenterVersion = service.IndenterVersion(), + Code = "Option Explicit\n\n'...comments...\n\nPublic Sub DoSomething()\n'...comments...\n\nEnd Sub\nPublic Sub DoSomethingElse()\n'...comments...\n\nIf True Then\nMsgBox \"Hello, world!\"\nElse\n'...comments...\nExit Sub\nEnd If\nEnd Sub\n", + AlignCommentsWithCode = true, + EmptyLineHandlingMethod = IndenterEmptyLineHandling.Indent, + ForceCompilerDirectivesInColumn1 = true, + GroupRelatedProperties = false, + IndentSpaces = 4, + IndentCase = true, + IndentEntireProcedureBody = true, + IndentEnumTypeAsProcedure = true, + VerticallySpaceProcedures = true, + LinesBetweenProcedures = 1, + IndentFirstCommentBlock = true, + IndentFirstDeclarationBlock = true, + EndOfLineCommentStyle = IndenterEndOfLineCommentStyle.SameGap, + }; + + return Ok(result); + }); + + [HttpPost("indenter/indent")] + [AllowAnonymous] + public IActionResult Indent(IndenterViewModel model) => + GuardInternalAction(() => + { + if (model is null) + { + throw new ArgumentNullException(nameof(model)); + } + + var result = service.IndentAsync(model).GetAwaiter().GetResult(); + return Ok(result); + }); +} diff --git a/rubberduckvba.Server/Program.cs b/rubberduckvba.Server/Program.cs index e867d05..3bc58fb 100644 --- a/rubberduckvba.Server/Program.cs +++ b/rubberduckvba.Server/Program.cs @@ -7,6 +7,7 @@ using NLog.Config; using NLog.Extensions.Logging; using NLog.Targets; +using Rubberduck.SmartIndenter; using RubberduckServices; using rubberduckvba.Server.Api.Admin; using rubberduckvba.Server.ContentSynchronization; @@ -42,6 +43,35 @@ public static void Main(string[] args) builder.Services.Configure(options => builder.Configuration.GetSection("Api").Bind(options)); builder.Services.Configure(options => builder.Configuration.GetSection("Hangfire").Bind(options)); + builder.Services.AddCors(builder => + { + builder.AddDefaultPolicy(policy => + { + policy + .SetIsOriginAllowed(origin => true) + .AllowAnyHeader() + .WithMethods("OPTIONS", "GET", "POST") + .AllowCredentials() + .Build(); + }); + + builder.AddPolicy("webhookPolicy", policy => + { + policy +#if DEBUG + .SetIsOriginAllowed(origin => true) +#else + .SetIsOriginAllowedToAllowWildcardSubdomains() + .WithOrigins("*.github.com") +#endif + .WithHeaders("Content-Type", "X-GitHub-Event", "X-GitHub-Delivery", "X-GitHub-Hook-ID", "X-Hub-Signature", "X-Hub-Signature256") + .WithMethods("POST") + .DisallowCredentials() + .SetPreflightMaxAge(TimeSpan.FromHours(48)) + .Build(); + }); + }); + builder.Services.AddAuthentication(options => { options.RequireAuthenticatedSignIn = false; @@ -88,22 +118,14 @@ public static void Main(string[] args) app.UseHttpsRedirection(); app.UseRouting(); - app.UseSession(); + app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); + app.UseSession(); app.MapControllers(); app.MapFallbackToFile("/index.html"); - app.UseCors(policy => - { - policy - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials() - .SetIsOriginAllowed(origin => true); - }); - StartHangfire(app); app.Run(); } @@ -162,6 +184,8 @@ private static void ConfigureServices(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/rubberduckvba.Server/RubberduckApiController.cs b/rubberduckvba.Server/RubberduckApiController.cs index 3e5125c..2f40dbf 100644 --- a/rubberduckvba.Server/RubberduckApiController.cs +++ b/rubberduckvba.Server/RubberduckApiController.cs @@ -17,39 +17,6 @@ protected RubberduckApiController(ILogger logger) protected ILogger Logger => _logger; - - protected async Task GuardInternalActionAsync(Func> method, [CallerMemberName] string name = default!) - { - var sw = Stopwatch.StartNew(); - IActionResult result = NoContent(); - var success = false; - try - { - _logger.LogTrace("GuardInternalActionAsync:{name} | ▶ Invoking controller action", name); - result = await method.Invoke(); - success = true; - } - catch (Exception exception) - { - _logger.LogError(exception, "GuardInternalActionAsync:{name} | ❌ An exception was caught", name); - throw; - } - finally - { - sw.Stop(); - if (success) - { - _logger.LogTrace("GuardInternalActionAsync:{name} | ✔️ Controller action completed | ⏱️ {elapsed}", name, sw.Elapsed); - } - else - { - _logger.LogWarning("GuardInternalActionAsync:{name} | ⚠️ Controller action completed with errors", name); - } - } - - return result; - } - protected IActionResult GuardInternalAction(Func method, [CallerMemberName] string name = default!) { var sw = Stopwatch.StartNew(); @@ -79,6 +46,7 @@ protected IActionResult GuardInternalAction(Func method, [CallerM } } + //Response.Headers.AccessControlAllowOrigin = "*"; return result; } } diff --git a/rubberduckvba.Server/rubberduckvba.Server.csproj b/rubberduckvba.Server/rubberduckvba.Server.csproj index e7a6e35..7af4d85 100644 --- a/rubberduckvba.Server/rubberduckvba.Server.csproj +++ b/rubberduckvba.Server/rubberduckvba.Server.csproj @@ -41,4 +41,10 @@ + + + ..\RubberduckServices\Libs\Rubberduck.SmartIndenter.dll + + + diff --git a/rubberduckvba.client/src/app/app.component.html b/rubberduckvba.client/src/app/app.component.html index 36f9caa..ad19940 100644 --- a/rubberduckvba.client/src/app/app.component.html +++ b/rubberduckvba.client/src/app/app.component.html @@ -1,11 +1,17 @@ - -
- -
-
-
+ +
+ +
+
+ +
+
+ +
+
+
© 2014-{{currentYear}} Rubberduck Project Contributors
diff --git a/rubberduckvba.client/src/app/app.component.ts b/rubberduckvba.client/src/app/app.component.ts index 5d8c5a9..58dc64c 100644 --- a/rubberduckvba.client/src/app/app.component.ts +++ b/rubberduckvba.client/src/app/app.component.ts @@ -1,4 +1,3 @@ -import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; @Component({ diff --git a/rubberduckvba.client/src/app/app.module.ts b/rubberduckvba.client/src/app/app.module.ts index 0427b9a..1c4f01b 100644 --- a/rubberduckvba.client/src/app/app.module.ts +++ b/rubberduckvba.client/src/app/app.module.ts @@ -1,16 +1,19 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; - -import { DataService } from './services/data.service'; -import { AdminApiClientService, ApiClientService } from './services/api-client.service'; +import { FormsModule } from '@angular/forms'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule, UrlSerializer } from '@angular/router'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; + +import { DataService } from './services/data.service'; +import { ApiClientService } from './services/api-client.service'; + import { AppComponent } from './app.component'; import { NavMenuComponent } from './components/nav-menu/nav-menu.component'; +import { LoadingContentComponent } from './components/loading-content/loading-content.component'; import { TagDownloadComponent } from './components/tag-download/tag-download.component'; import { DownloadItemComponent } from './components/download-item/download-item.component'; import { FeatureBoxComponent } from './components/feature-box/feature-box.component'; @@ -18,7 +21,6 @@ import { FeatureInfoComponent } from './components/feature-info/feature-info.com import { FeatureItemBoxComponent } from './components/feature-item-box/feature-item-box.component'; import { ExampleBoxComponent } from './components/example-box/example-box.component'; import { FeatureItemExampleComponent } from './components/quickfix-example.modal/quickfix-example.modal.component'; -import { LoadingContentComponent } from './components/loading-content/loading-content.component'; import { InspectionItemBoxComponent } from './components/feature-item-box/inspection-item-box/inspection-item-box.component'; import { AnnotationItemBoxComponent } from './components/feature-item-box/annotation-item-box/annotation-item-box.component'; import { BlogLinkBoxComponent } from './components/blog-link-box/blog-link-box.component'; @@ -31,10 +33,11 @@ import { FeatureComponent } from './routes/feature/feature.component'; import { InspectionComponent } from './routes/inspection/inspection.component'; import { AnnotationComponent } from './routes/annotation/annotation.component'; import { QuickFixComponent } from './routes/quickfixes/quickfix.component'; +import { IndenterComponent } from './routes/indenter/indenter.component'; import { DefaultUrlSerializer, UrlTree } from '@angular/router'; -import { AuthMenuComponent } from './components/auth-menu/auth-menu.component'; import { AuthComponent } from './routes/auth/auth.component'; +import { AuthMenuComponent } from './components/auth-menu/auth-menu.component'; /** * https://stackoverflow.com/a/39560520 @@ -55,6 +58,8 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { AppComponent, HomeComponent, AuthComponent, + AuthMenuComponent, + IndenterComponent, FeaturesComponent, FeatureComponent, TagDownloadComponent, @@ -73,13 +78,13 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { InspectionComponent, AnnotationComponent, QuickFixComponent, - AboutComponent, - AuthMenuComponent + AboutComponent ], bootstrap: [AppComponent], imports: [ - BrowserModule, CommonModule, + BrowserModule, + FormsModule, RouterModule.forRoot([ { path: '', component: HomeComponent, pathMatch: 'full' }, { path: 'features', component: FeaturesComponent }, @@ -89,6 +94,7 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { { path: 'quickfixes/:name', component: QuickFixComponent }, { path: 'about', component: AboutComponent }, { path: 'auth/github', component: AuthComponent }, + { path: 'indenter', component: IndenterComponent }, // legacy routes: { path: 'inspections/details/:name', redirectTo: 'inspections/:name' }, ]), @@ -98,7 +104,6 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { providers: [ DataService, ApiClientService, - AdminApiClientService, provideHttpClient(withInterceptorsFromDi()), { provide: UrlSerializer, @@ -106,4 +111,5 @@ export class LowerCaseUrlSerializer extends DefaultUrlSerializer { } ] }) + export class AppModule { } diff --git a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts index eb1c88b..672b29c 100644 --- a/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts +++ b/rubberduckvba.client/src/app/components/auth-menu/auth-menu.component.ts @@ -1,4 +1,3 @@ -/// import { Component, OnInit, TemplateRef, ViewChild, inject } from "@angular/core"; import { FaIconLibrary } from "@fortawesome/angular-fontawesome"; import { BehaviorSubject } from "rxjs"; @@ -6,8 +5,8 @@ import { UserViewModel } from "../../model/feature.model"; import { AuthService } from "src/app/services/auth.service"; import { fas } from "@fortawesome/free-solid-svg-icons"; import { fab } from "@fortawesome/free-brands-svg-icons"; -import { NgbModal, NgbToast } from "@ng-bootstrap/ng-bootstrap"; -import { AdminApiClientService, ApiClientService } from "../../services/api-client.service"; +import { NgbModal } from "@ng-bootstrap/ng-bootstrap"; +import { ApiClientService } from "../../services/api-client.service"; @Component({ selector: 'auth-menu', @@ -29,7 +28,7 @@ export class AuthMenuComponent implements OnInit { @ViewChild('confirmxmldocsbox', { read: TemplateRef }) confirmxmldocsbox: TemplateRef | undefined; public modal = inject(NgbModal); - constructor(private auth: AuthService, private api: AdminApiClientService, private fa: FaIconLibrary) { + constructor(private auth: AuthService, private api: ApiClientService, private fa: FaIconLibrary) { fa.addIconPacks(fas); fa.addIconPacks(fab); } diff --git a/rubberduckvba.client/src/app/components/example-box/example-box.component.html b/rubberduckvba.client/src/app/components/example-box/example-box.component.html index 02d004d..d4a189c 100644 --- a/rubberduckvba.client/src/app/components/example-box/example-box.component.html +++ b/rubberduckvba.client/src/app/components/example-box/example-box.component.html @@ -1,7 +1,7 @@
-