Skip to content

Commit

Permalink
Merge pull request #1754 from pkuehnel/feat/improveCloudConnectUi
Browse files Browse the repository at this point in the history
feat(CloudConnectionRazor): improve UI for backend and fleet api token
  • Loading branch information
pkuehnel authored Jan 18, 2025
2 parents 53bbc14 + 65be498 commit eb67a57
Show file tree
Hide file tree
Showing 19 changed files with 243 additions and 133 deletions.
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Client/Dialogs/AddCarDialog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ else if (_fleetApiTokenState != TokenState.UpToDate)
NoIcon="true"
ContentAlignment="HorizontalAlignment.Left">
<h4>Tesla Fleet API Token is not valid.</h4>
Go to <MudLink Href="/BaseConfiguration">Base Configuration</MudLink> and Generate a Tesla Fleet API Token.
Go to <MudLink Href="/cloudconnection">Cloud Connection</MudLink> and Generate a Tesla Fleet API Token.
</MudAlert>
}
else
Expand Down
69 changes: 1 addition & 68 deletions TeslaSolarCharger/Client/Pages/BaseConfiguration.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
@inject IHttpClientHelper HttpClientHelper
@inject IBackendApiTokenCheckService BackendApiTokenCheckService
@inject ICloudConnectionCheckService CloudConnectionCheckService
@inject IDialogHelper DialogHelper


Expand All @@ -34,44 +34,6 @@ else
</InputFragment>
</InputComponent>
<hr />
<h3>Tesla Fleet API:</h3>
@switch (_fleetApiTokenState)
{
case TokenState.MissingPrecondition:
<div>
You are not logged in in the Solar4car.com account. When requesting a new Tesla Token there will also be a request to log in to your Solar4car.com account.
</div>
break;
case TokenState.NotAvailable:
<div>
You did not request a Fleet API Token, yet. Request a new token, allow access to all scopes and enable mobile access in your car.
</div>
break;
case TokenState.Unauthorized:
<div>
Your token is unauthorized. Request a new token, allow access to all scopes and enable mobile access in your car.
</div>
break;
case TokenState.MissingScopes:
<div>
Your token has missing scopes. Request a new Token and allow all scopes (only required scopes are requested).
</div>
break;
case TokenState.Expired:
<div>
Your Fleet API token is expired. Request a new Token and allow all scopes (only required scopes are requested).
</div>
break;
case TokenState.UpToDate:
<div>
Everything is fine! If you want to generate a new token e.g. to switch to another Tesla Account please click the button below:
</div>
break;
}
<div>
<button class="btn btn-primary" disabled="@_tokenGenerationButtonDisabled" type="button" @onclick="GenerateFleetApiToken">Request Token</button>
</div>
<hr />
<h3>TeslaMate:</h3>
<GenericInput T="bool"
For="() => _dtoBaseConfiguration.UseTeslaMateIntegration"
Expand Down Expand Up @@ -275,21 +237,12 @@ else
@code {
private DtoBaseConfiguration? _dtoBaseConfiguration;

private TokenState? _fleetApiTokenState;

private bool _tokenGenerationButtonDisabled;

private bool _telegramSettingsChanged;
private bool _submitLoading;

protected override async Task OnInitializedAsync()
{
_dtoBaseConfiguration = await HttpClient.GetFromJsonAsync<DtoBaseConfiguration>("/api/BaseConfiguration/GetBaseConfiguration").ConfigureAwait(false);
var value = await HttpClient.GetFromJsonAsync<DtoValue<TokenState>>("api/FleetApi/FleetApiTokenState").ConfigureAwait(false);
if (value != null)
{
_fleetApiTokenState = value.Value;
}
}

private async Task HandleValidSubmit()
Expand All @@ -309,26 +262,6 @@ else
_submitLoading = false;
}

private async Task GenerateFleetApiToken()
{
_tokenGenerationButtonDisabled = true;
var locale = CultureInfo.CurrentCulture.ToString();
var baseUrl = NavigationManager.BaseUri;
var backendTokenState = await BackendApiTokenCheckService.GetTokenState(false);
if (backendTokenState != TokenState.UpToDate)
{
Snackbar.Add("You need to be logged in to Solar4Car.com to generate a Fleet API Token", Severity.Error);
NavigationManager.NavigateTo("cloudconnection");
return;
}

var url = await HttpClient.GetFromJsonAsync<DtoValue<string>>($"api/FleetApi/GetOauthUrl?locale={Uri.EscapeDataString(locale)}&baseUrl={Uri.EscapeDataString(baseUrl)}").ConfigureAwait(false);
if (url?.Value != null)
{
NavigationManager.NavigateTo(url.Value);
}
}


private string _correctionFactorHelpText = "Use this to correct the returned value. E.g. if the returned value is 1 but should bei -1 insert -1";

Expand Down
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Client/Pages/CarSettings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
NoIcon="true"
ContentAlignment="HorizontalAlignment.Left">
<h4>Create Token.</h4>
Go to <MudLink Href="/BaseConfiguration">Base Configuration</MudLink>, Generate a Tesla Fleet API Token and restart TSC to see cars here.
Go to <MudLink Href="/cloudconnection">Cloud Connection</MudLink>, Generate a Tesla Fleet API Token and restart TSC to see cars here.
</MudAlert>
}
@if (_fleetApiTokenState == TokenState.UpToDate)
Expand Down
171 changes: 145 additions & 26 deletions TeslaSolarCharger/Client/Pages/CloudConnection.razor
Original file line number Diff line number Diff line change
@@ -1,59 +1,103 @@
@page "/cloudconnection"
@using System.Globalization
@using TeslaSolarCharger.Client.Helper.Contracts
@using TeslaSolarCharger.Client.Services.Contracts
@using TeslaSolarCharger.Shared.Dtos
@using TeslaSolarCharger.Shared.Enums

@inject IHttpClientHelper HttpClientHelper
@inject IBackendApiTokenCheckService IBackendApiTokenCheckService
@inject ICloudConnectionCheckService CloudConnectionCheckService
@inject ISnackbar Snackbar
@inject NavigationManager NavigationManager

<h1>Backend Connection</h1>

<MudAlert Severity="Severity.Warning"
NoIcon="true"
ShowCloseIcon="false">
<div>You need to create a <MudLink Href="https://solar4car.com/Account/Register?returnUrl=https%3A%2F%2Fsolar4car.com%2Fsubscriptions">Solar4Car.com account</MudLink> and create at least a base app subscription before you can proceed.</div>
</MudAlert>
<h1>Cloud Connection</h1>

<h3>Solar4Car Backend connection</h3>
@if (BackendTokenState == default)
{
<PlaceholderComponent></PlaceholderComponent>
}
else
{
<MudAlert Severity="@Severity"
NoIcon="true"
ShowCloseIcon="false">
<div>@TokenStateText</div>
<MudAlert Severity="@BackendTokenAlertSeverity"
NoIcon="true"
ShowCloseIcon="false">
<div>@BackendTokenStateText</div>
</MudAlert>
}

<GenericInput For="() => _backendLogin.UserName"></GenericInput>
<GenericInput For="() => _backendLogin.Password"
IsPassword="true"></GenericInput>

@if (LoginErrorMessage != default)
@if (BackendTokenState == TokenState.UpToDate)
{
<div class="validation-message">
Login failed: @LoginErrorMessage
@if (LoggedInUserName == default)
{
<div>Logged in as unknown user</div>
}
else
{
<div>Logged in as @LoggedInUserName</div>
}
<RightAlignedButtonComponent OnButtonClicked="FakeLogout"
ButtonText="ChangeUser" />
}
else
{
<GenericInput For="() => _backendLogin.EMail"></GenericInput>
<GenericInput For="() => _backendLogin.Password"
IsPassword="true"></GenericInput>
@if (LoginErrorMessage != default)
{
<div class="validation-message">
Login failed: @LoginErrorMessage
</div>
}
<RightAlignedButtonComponent OnButtonClicked="Submit"
ButtonText="Login"
IsLoading="@_backendLoginIsLoading">
</RightAlignedButtonComponent>
<div class="d-flex">
<MudSpacer></MudSpacer><MudLink Href="https://solar4car.com/Account/Register?returnUrl=https%3A%2F%2Fsolar4car.com%2Fsubscriptions" Target="_blank">Register</MudLink>
</div>

}

<RightAlignedButtonComponent OnButtonClicked="Submit"
ButtonText="Login">
</RightAlignedButtonComponent>
<h3>Tesla Fleet API Connection</h3>
@if (FleetApiTokenState == default)
{
<PlaceholderComponent></PlaceholderComponent>
}
else
{
<MudAlert Severity="@FleetApiTokenAlertSeverity"
NoIcon="true"
ShowCloseIcon="false">
<div>@FleetApiTokenStateText</div>
</MudAlert>
<div class="mt-2">
<RightAlignedButtonComponent OnButtonClicked="GenerateFleetApiToken"
ButtonText="Request Token"
IsLoading="@_fleetApiLoginIsLoading"
IsDisabled="@(BackendTokenState != TokenState.UpToDate)">
</RightAlignedButtonComponent>
</div>
}


@code {
private readonly DtoBackendLogin _backendLogin = new DtoBackendLogin();

private bool _backendLoginIsLoading;
private bool _fleetApiLoginIsLoading;

private string? LoginErrorMessage { get; set; }

private TokenState? BackendTokenState { get; set; }
private TokenState? FleetApiTokenState { get; set; }
private string? LoggedInUserName { get; set; }

private Severity Severity => BackendTokenState == TokenState.UpToDate ? Severity.Success : Severity.Error;
private Severity BackendTokenAlertSeverity => BackendTokenState == TokenState.UpToDate ? Severity.Success : Severity.Error;
private Severity FleetApiTokenAlertSeverity => FleetApiTokenState == TokenState.UpToDate ? Severity.Success : Severity.Error;

private string TokenStateText
private string BackendTokenStateText
{
get
{
Expand All @@ -79,15 +123,90 @@ ButtonText="Login">
}
}

private string FleetApiTokenStateText
{
get
{
switch (FleetApiTokenState)
{
case TokenState.MissingPrecondition:
return "You are not logged in in the Solar4car.com account. When requesting a new Tesla Token there will also be a request to log in to your Solar4car.com account.";
case TokenState.NotAvailable:
return "You did not request a Fleet API Token, yet. Request a new token, allow access to all scopes and enable mobile access in your car.";
case TokenState.Unauthorized:
return "Your token is unauthorized. Request a new token, allow access to all scopes and enable mobile access in your car.";
case TokenState.MissingScopes:
return "Your token has missing scopes. Request a new Token and allow all scopes (only required scopes are requested).";
case TokenState.Expired:
return "Your Fleet API token is expired. Request a new Token and allow all scopes (only required scopes are requested).";
case TokenState.UpToDate:
return "Everything is fine! If you want to generate a new token e.g. to switch to another Tesla Account please click the button below:";
case null:
return "Could not check Token state. Is your TSC connected to the internet?";
default:
throw new ArgumentOutOfRangeException();
}
}
}

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
BackendTokenState = await IBackendApiTokenCheckService.GetTokenState(false);
await RefreshData();

}

private async Task RefreshData()
{
BackendTokenState = await CloudConnectionCheckService.GetBackendTokenState(false);
LoggedInUserName = await CloudConnectionCheckService.GetBackendTokenUserName();
FleetApiTokenState = await CloudConnectionCheckService.GetFleetApiTokenState(false);
}

private async Task Submit()
{
_backendLoginIsLoading = true;
var result = await HttpClientHelper.SendPostRequestAsync("api/BackendApi/LoginToBackend", _backendLogin);
LoginErrorMessage = result.HasError ? result.ErrorMessage : default;
if (result.HasError)
{
LoginErrorMessage = result.ErrorMessage;
Snackbar.Add("Login did not succeed", Severity.Error);
}
else
{
LoginErrorMessage = default;
Snackbar.Add("Login succeeded", Severity.Success);
}

await RefreshData();
_backendLoginIsLoading = false;
StateHasChanged();
}

private void FakeLogout()
{
BackendTokenState = TokenState.NotAvailable;
LoggedInUserName = default;
StateHasChanged();
}

private async Task GenerateFleetApiToken()
{
_fleetApiLoginIsLoading = true;
var locale = CultureInfo.CurrentCulture.ToString();
if (BackendTokenState != TokenState.UpToDate)
{
Snackbar.Add("You need to be logged in to Solar4Car.com to generate a Fleet API Token", Severity.Error);
return;
}
var baseUrl = NavigationManager.BaseUri;
var url = await CloudConnectionCheckService.GetTeslaLoginUrl(locale, baseUrl + "cloudconnection");
if (string.IsNullOrEmpty(url))
{
Snackbar.Add("Could not generate Tesla Login URL", Severity.Error);
return;
}
NavigationManager.NavigateTo(url);
}

}
2 changes: 1 addition & 1 deletion TeslaSolarCharger/Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
builder.Services.AddScoped<IDialogHelper, DialogHelper>();
builder.Services.AddScoped<IJavaScriptWrapper, JavaScriptWrapper>();
builder.Services.AddScoped<IHttpClientHelper, HttpClientHelper>();
builder.Services.AddScoped<IBackendApiTokenCheckService, BackendApiTokenCheckService>();
builder.Services.AddScoped<ICloudConnectionCheckService, CloudConnectionCheckService>();
builder.Services.AddSingleton<ToolTipTextKeys>();
builder.Services.AddSharedDependencies();
builder.Services.AddMudServices(config =>
Expand Down
15 changes: 0 additions & 15 deletions TeslaSolarCharger/Client/Services/BackendApiTokenCheckService.cs

This file was deleted.

Loading

0 comments on commit eb67a57

Please sign in to comment.