From 32033684fb473ab92291c7c268303325b49618d2 Mon Sep 17 00:00:00 2001 From: Alberto Spelta Date: Fri, 10 Jul 2026 13:01:34 +0200 Subject: [PATCH] Fix sign-in flow to properly cancel pending requests on user cancellation Abort the pending sign-in request when the user cancels the dialog, instead of leaving it pending until the hard timeout expires, and scope the timeout ceiling to the system browser flow only, since the embedded browser already cancels correctly on its own. Normalize all sign-in cancellation paths (embedded/system browser MSAL cancellation, timeout, explicit user abort) to a single OperationCanceledException, handled by responding 204 No Content instead of an error, and remove the now-unused SignInMsalTimeoutExpired problem code and its telemetry noise across all locales. --- src/Controllers/AuthenticationController.cs | 21 +++++++++++++------ src/Infrastructure/AppExceptions.cs | 12 +++-------- .../Extensions/MsalExceptionExtensions.cs | 14 +++++++++++++ .../CloudAuthenticationClient.cs | 20 +++++++++++++++++- .../CloudAuthenticationService.cs | 7 ++----- src/Scripts/controllers/host.ts | 2 +- src/Scripts/model/exceptions.ts | 1 - src/Scripts/model/i18n/cz.ts | 1 - src/Scripts/model/i18n/da.ts | 1 - src/Scripts/model/i18n/de.ts | 1 - src/Scripts/model/i18n/en.ts | 1 - src/Scripts/model/i18n/es.ts | 1 - src/Scripts/model/i18n/fa.ts | 1 - src/Scripts/model/i18n/fr.ts | 1 - src/Scripts/model/i18n/gr.ts | 1 - src/Scripts/model/i18n/it.ts | 1 - src/Scripts/model/i18n/nl.ts | 1 - src/Scripts/model/i18n/pl.ts | 1 - src/Scripts/model/i18n/pt.ts | 1 - src/Scripts/model/i18n/ru.ts | 1 - src/Scripts/model/i18n/tr.ts | 1 - src/Scripts/model/i18n/uk.ts | 1 - src/Scripts/model/i18n/zh.ts | 1 - src/Scripts/model/strings.ts | 1 - src/Scripts/view/powerbi-signin.ts | 5 ++++- src/Services/AuthenticationService.cs | 19 ++--------------- 26 files changed, 60 insertions(+), 58 deletions(-) create mode 100644 src/Infrastructure/Extensions/MsalExceptionExtensions.cs diff --git a/src/Controllers/AuthenticationController.cs b/src/Controllers/AuthenticationController.cs index 0009f65c..eabaa04a 100644 --- a/src/Controllers/AuthenticationController.cs +++ b/src/Controllers/AuthenticationController.cs @@ -50,22 +50,31 @@ public async Task GetEnvironmentsAsync( /// Attempts to authenticate and acquire an access token for the account to access the PowerBI cloud services /// /// Status200OK - Success + /// Status204NoContent - Sign-in was canceled by the user [HttpPost] [ActionName("SignIn")] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SignInResponse))] + [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesDefaultResponseType] public async Task SignInAsync( SignInRequest request, CancellationToken cancellationToken) { - var session = await _authenticationService.SignInAsync( - request.Email, - request.Environment.ToModel(), - cancellationToken); + try + { + var session = await _authenticationService.SignInAsync( + request.Email, + request.Environment.ToModel(), + cancellationToken); - var response = new SignInResponse(session.AuthenticationResult); - return Ok(response); + var response = new SignInResponse(session.AuthenticationResult); + return Ok(response); + } + catch (OperationCanceledException) + { + return NoContent(); + } } /// diff --git a/src/Infrastructure/AppExceptions.cs b/src/Infrastructure/AppExceptions.cs index d8d6757b..ea4fbf2e 100644 --- a/src/Infrastructure/AppExceptions.cs +++ b/src/Infrastructure/AppExceptions.cs @@ -115,8 +115,8 @@ public enum BravoProblem None = 0, /// - /// A or was thrown, an HTTP request was aborted or the user cancelled a long-running operation. - /// This BravoProblem is a placehoder since the response message is never sent back to the user/UI due to the aborted request. + /// An was thrown (request aborted or user-cancelled operation). + /// Response message is not sent to the user/UI due to the aborted request. /// [JsonPropertyName("OperationCancelled")] OperationCancelled = 1, @@ -172,15 +172,9 @@ public enum BravoProblem [JsonPropertyName("SignInMsalExceptionOccurred")] SignInMsalExceptionOccurred = 400, - /// - /// Sign-in request was canceled because the configured timeout period elapsed prior to completion of the operation - /// - [JsonPropertyName("SignInMsalTimeoutExpired")] - SignInMsalTimeoutExpired = 401, - /// /// An error occurred while importing the VPAX file - /// + /// [JsonPropertyName("VpaxFileImportError")] VpaxFileImportError = 500, diff --git a/src/Infrastructure/Extensions/MsalExceptionExtensions.cs b/src/Infrastructure/Extensions/MsalExceptionExtensions.cs new file mode 100644 index 00000000..46e9a636 --- /dev/null +++ b/src/Infrastructure/Extensions/MsalExceptionExtensions.cs @@ -0,0 +1,14 @@ +namespace Sqlbi.Bravo.Infrastructure.Extensions +{ + using Microsoft.Identity.Client; + + internal static class MsalExceptionExtensions + { + /// + /// Returns if the exception represents the user canceling + /// an interactive authentication prompt (e.g. closing the sign-in window). + /// + public static bool IsAuthenticationCanceled(this MsalException exception) + => exception.ErrorCode == MsalError.AuthenticationCanceledError; + } +} diff --git a/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationClient.cs b/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationClient.cs index 0c11f2cb..385ed257 100644 --- a/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationClient.cs +++ b/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationClient.cs @@ -3,6 +3,7 @@ namespace Sqlbi.Bravo.Infrastructure.PowerBI.Cloud.Authentication using Microsoft.Identity.Client; using Microsoft.Identity.Client.Desktop; using Sqlbi.Bravo.Infrastructure.Configuration; + using Sqlbi.Bravo.Infrastructure.Extensions; using Sqlbi.Bravo.Infrastructure.Helpers; using Sqlbi.Bravo.Infrastructure.PowerBI.Cloud; using Msal = Microsoft.Identity.Client; @@ -89,13 +90,30 @@ public async Task ClearTokenCacheAsync(CloudEnvironment environment) .WithPrompt(prompt) .WithClaims(claims); + using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + if (useEmbeddedBrowser) { var windowHandle = ProcessHelper.GetCurrentProcessMainWindowHandle(); builder.WithParentActivityOrWindow(windowHandle); } + else // use system browser + { + // The system browser is a separate, untracked OS process: there is no way to detect the user closing + // it, so a hard ceiling is the only safeguard against an indefinitely pending sign-in. + cancellationTokenSource.CancelAfter(TimeSpan.FromMinutes(2)); + } - return await builder.ExecuteAsync(cancellationToken).ConfigureAwait(false); + try + { + return await builder.ExecuteAsync(cancellationTokenSource.Token).ConfigureAwait(false); + } + catch (MsalException ex) when (ex.IsAuthenticationCanceled()) + { + // The user canceled the sign-in prompt, either by closing the embedded browser or the system browser. + // Normalize the exception to OperationCanceledException, like the other cancellation paths + throw new OperationCanceledException("Authentication was canceled by the user.", ex); + } } private static IPublicClientApplication CreatePublicClient(CloudEnvironment environment) diff --git a/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationService.cs b/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationService.cs index a4f50684..df47508d 100644 --- a/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationService.cs +++ b/src/Infrastructure/PowerBI/Cloud/Authentication/CloudAuthenticationService.cs @@ -35,11 +35,8 @@ public async Task SignInAsync(string email, CloudEnvironme if (AppEnvironment.IsDiagnosticLevelVerbose) AppEnvironment.AddDiagnostics(DiagnosticMessageType.Json, name: $"{nameof(CloudAuthenticationService)}.{nameof(SignInAsync)}", JsonSerializer.Serialize(environment)); - using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cancellationTokenSource.CancelAfter(TimeSpan.FromMinutes(2)); - - var authenticationResult = await _cloudAuthenticationClient.AcquireTokenAsync(environment, email, cancellationTokenSource.Token); - var clusterUri = await _cloudConfigurationService.ResolveTenantClusterUriAsync(environment, authenticationResult.AccessToken, cancellationTokenSource.Token); + var authenticationResult = await _cloudAuthenticationClient.AcquireTokenAsync(environment, email, cancellationToken); + var clusterUri = await _cloudConfigurationService.ResolveTenantClusterUriAsync(environment, authenticationResult.AccessToken, cancellationToken); var newEnvironment = environment with { ClusterUri = clusterUri }; var newSession = new AuthenticatedSession(authenticationResult, newEnvironment); diff --git a/src/Scripts/controllers/host.ts b/src/Scripts/controllers/host.ts index 8b4c0e10..b4499e18 100644 --- a/src/Scripts/controllers/host.ts +++ b/src/Scripts/controllers/host.ts @@ -398,7 +398,7 @@ export class Host extends Dispatchable { const logSettings: ApiLogSettings = {}; return (>this.apiCall("auth/SignIn", request || {}, { method: "POST" }, false, logSettings)) - .then(response => response.account); + .then(response => response?.account); } /*signIn(email?: string) { diff --git a/src/Scripts/model/exceptions.ts b/src/Scripts/model/exceptions.ts index b276d97b..04792bbd 100644 --- a/src/Scripts/model/exceptions.ts +++ b/src/Scripts/model/exceptions.ts @@ -22,7 +22,6 @@ export enum AppProblem { ConnectionUnsupported = 200, UserSettingsSaveError = 300, SignInMsalExceptionOccurred = 400, - SignInMsalTimeoutExpired = 401, VpaxFileImportError = 500, VpaxFileExportError = 501, NetworkError = 600, diff --git a/src/Scripts/model/i18n/cz.ts b/src/Scripts/model/i18n/cz.ts index eedd1794..57011d96 100644 --- a/src/Scripts/model/i18n/cz.ts +++ b/src/Scripts/model/i18n/cz.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Nejsou k dispozici žádné neotevřené chyby.", [_.errorRetry]: "Opakovat", [_.errorSignInMsalExceptionOccurred]: "Neočekávaná chyba v rámci přihlášení.", - [_.errorSignInMsalTimeoutExpired]: "Požadavek na přihlášení byl zrušen, protože časový limit vypršel před dokončením operace.", [_.errorTemplateAlreadyExists]: "Další šablona se stejnou cestou již existuje:
{name}", [_.errorTimeout]: "Časový limit požadavku vypršel.", [_.errorTitle]: "Whoops...", diff --git a/src/Scripts/model/i18n/da.ts b/src/Scripts/model/i18n/da.ts index 9c1d5e38..57816158 100644 --- a/src/Scripts/model/i18n/da.ts +++ b/src/Scripts/model/i18n/da.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Ingen uåbnede rapporter tilgængelige.", [_.errorRetry]: "Forsøg igen", [_.errorSignInMsalExceptionOccurred]: "Ukendt fejl opstod i forbindelse med lo- ind.", - [_.errorSignInMsalTimeoutExpired]: "Log-ind blev afbrudt fordi timeout perioden udløb inden processen blev gennemført.", [_.errorTemplateAlreadyExists]: "En anden skabelon med den samme sti findes allerede:
{name}", [_.errorTimeout]: "Forespørgselstimeout.", [_.errorTitle]: "Ups...", diff --git a/src/Scripts/model/i18n/de.ts b/src/Scripts/model/i18n/de.ts index 24d93d77..7ac52ffe 100644 --- a/src/Scripts/model/i18n/de.ts +++ b/src/Scripts/model/i18n/de.ts @@ -158,7 +158,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Keine ungeöffneten Berichte verfügbar.", [_.errorRetry]: "Wiederholen", [_.errorSignInMsalExceptionOccurred]: "Unerwarteter Fehler in der Anmeldeanforderung.", - [_.errorSignInMsalTimeoutExpired]: "Die Anmeldeanforderung wurde abgebrochen, weil die Zeitüberschreitung abgelaufen ist, bevor der Vorgang abgeschlossen werden konnte.", [_.errorTemplateAlreadyExists]: "Eine weitere Vorlage mit dem gleichen Weg gibt es bereits:
{name}", [_.errorTimeout]: "Zeitüberschreitung der Anfrage.", [_.errorTitle]: "Ups...", diff --git a/src/Scripts/model/i18n/en.ts b/src/Scripts/model/i18n/en.ts index 7bc23acd..d9900152 100644 --- a/src/Scripts/model/i18n/en.ts +++ b/src/Scripts/model/i18n/en.ts @@ -157,7 +157,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "No unopened reports available.", [_.errorRetry]: "Retry", [_.errorSignInMsalExceptionOccurred]: "Unexpected error in the sign-in request.", - [_.errorSignInMsalTimeoutExpired]: "The sign-in request was canceled because the timeout period expired before the operation was completed.", [_.errorTemplateAlreadyExists]: "Another template with the same path/name already exists:
{name}", [_.errorTimeout]: "Request timeout.", [_.errorTitle]: "Whoops...", diff --git a/src/Scripts/model/i18n/es.ts b/src/Scripts/model/i18n/es.ts index ed5e143d..57404afe 100644 --- a/src/Scripts/model/i18n/es.ts +++ b/src/Scripts/model/i18n/es.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "No hay informes sin abrir disponibles.", [_.errorRetry]: "Reintentar", [_.errorSignInMsalExceptionOccurred]: "Error inesperado en la solicitud de inicio de sesión.", - [_.errorSignInMsalTimeoutExpired]: "La solicitud de inicio de sesión se canceló porque el tiempo de espera expiró antes de que se completara la operación.", [_.errorTemplateAlreadyExists]: "¡Ya existe otra plantilla con el mismo camino:
{name}", [_.errorTimeout]: "Su solicitud ha expirado", [_.errorTitle]: "Ups…", diff --git a/src/Scripts/model/i18n/fa.ts b/src/Scripts/model/i18n/fa.ts index 9ce51e0a..32fbf7b2 100644 --- a/src/Scripts/model/i18n/fa.ts +++ b/src/Scripts/model/i18n/fa.ts @@ -160,7 +160,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "هیچ گزارش باز نشده ای موجود نیست.", [_.errorRetry]: "تلاش مجدد", [_.errorSignInMsalExceptionOccurred]: "خطای غیرمنتظره در درخواست ورود به سیستم.", - [_.errorSignInMsalTimeoutExpired]: "درخواست ورود به سیستم لغو شد زیرا دوره وقفه قبل از تکمیل عملیات منقضی شده بود.", [_.errorTemplateAlreadyExists]: "الگوی دیگری با همان مسیر/نام از قبل وجود دارد:
{name}", [_.errorTimeout]: "زمان پایان درخواست.", [_.errorTitle]: "اوه...", diff --git a/src/Scripts/model/i18n/fr.ts b/src/Scripts/model/i18n/fr.ts index c451d72a..b28b6f07 100644 --- a/src/Scripts/model/i18n/fr.ts +++ b/src/Scripts/model/i18n/fr.ts @@ -158,7 +158,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Aucun rapport disponible.", [_.errorRetry]: "Réessayer", [_.errorSignInMsalExceptionOccurred]: "Erreur inattendue lors de l'authentification.", - [_.errorSignInMsalTimeoutExpired]: "La demande d'authentification a été annulée suite à l'expiration du timeout.", [_.errorTemplateAlreadyExists]: "Un autre modèle avec le même chemin existe déjà:
{name}", [_.errorTimeout]: "Timeout sur la demande.", [_.errorTitle]: "Oops...", diff --git a/src/Scripts/model/i18n/gr.ts b/src/Scripts/model/i18n/gr.ts index b592566d..91f08cbc 100644 --- a/src/Scripts/model/i18n/gr.ts +++ b/src/Scripts/model/i18n/gr.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Δεν υπάρχουν διαθέσιμες ανοικτές αναφορές.", [_.errorRetry]: "Εκ νέου προσπάθεια", [_.errorSignInMsalExceptionOccurred]: "Αναπάντεχο σφάλμα κατά την προσπάθεια σύνδεσης.", - [_.errorSignInMsalTimeoutExpired]: "Η προσπάθεια σύνδεσης διακόπηκε επειδή πέρασε ο χρόνος εξαιτίας λήξης του χρόνου που έχει οριστεί για την ολοκλήρωση της(timeout).", [_.errorTemplateAlreadyExists]: "Ένα άλλο πρότυπο με το ίδιο μονοπάτι υπάρχει ήδη:
{name}", [_.errorTimeout]: "Λήξη χρόνου(timeout).", [_.errorTitle]: "Όυπςςς", diff --git a/src/Scripts/model/i18n/it.ts b/src/Scripts/model/i18n/it.ts index af213343..a2929158 100644 --- a/src/Scripts/model/i18n/it.ts +++ b/src/Scripts/model/i18n/it.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Nessun altro report aperto.", [_.errorRetry]: "Riprova", [_.errorSignInMsalExceptionOccurred]: "Errore inaspettato durante l'accesso.", - [_.errorSignInMsalTimeoutExpired]: "La richiesta di accesso è stata annullata perché è passato troppo tempo prima che l'operazione venisse completata.", [_.errorTemplateAlreadyExists]: "Un altro template con lo stesso percorso/nome esiste già:
{name}", [_.errorTimeout]: "Timeout.", [_.errorTitle]: "Oops...", diff --git a/src/Scripts/model/i18n/nl.ts b/src/Scripts/model/i18n/nl.ts index f23b51ab..63d76b7e 100644 --- a/src/Scripts/model/i18n/nl.ts +++ b/src/Scripts/model/i18n/nl.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Geen ongeopende rapporten beschikbaar.", [_.errorRetry]: "Opnieuw proberen", [_.errorSignInMsalExceptionOccurred]: "Onverwachte fout in het inlogverzoek.", - [_.errorSignInMsalTimeoutExpired]: "Het inlogverzoek is geannuleerd vanwege een onderbreking die optrad voordat het verzoek voltooid kon worden.", [_.errorTemplateAlreadyExists]: "Er bestaat al een ander sjabloon met hetzelfde pad:
{name}", [_.errorTimeout]: "Verzoek onderbroken.", [_.errorTitle]: "Oeps...", diff --git a/src/Scripts/model/i18n/pl.ts b/src/Scripts/model/i18n/pl.ts index ff6b7031..70b4eaff 100644 --- a/src/Scripts/model/i18n/pl.ts +++ b/src/Scripts/model/i18n/pl.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Brak dostępnych, nieotwartych raportów.", [_.errorRetry]: "Spróbuj ponownie", [_.errorSignInMsalExceptionOccurred]: "Nieoczekiwany błąd w trakcie logowania.", - [_.errorSignInMsalTimeoutExpired]: "Logowanie zostało anulowane ponieważ czas opracji przekroczył dozwolony.", [_.errorTemplateAlreadyExists]: "Kolejny szablon z tą samą ścieżką już istnieje:
{name}", [_.errorTimeout]: "Limit czasu żądania.", [_.errorTitle]: "Whoops...", diff --git a/src/Scripts/model/i18n/pt.ts b/src/Scripts/model/i18n/pt.ts index 0f94294d..9197a461 100644 --- a/src/Scripts/model/i18n/pt.ts +++ b/src/Scripts/model/i18n/pt.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Nenhum relatório por abrir disponível.", [_.errorRetry]: "Tente novamente", [_.errorSignInMsalExceptionOccurred]: "Erro inesperado no pedido de início de sessão.", - [_.errorSignInMsalTimeoutExpired]: "O pedido de início de sessão foi cancelado porque o tempo limite foi excedido antes da operação estar terminada.", [_.errorTemplateAlreadyExists]: "Outro modelo com o mesmo caminho já existe:
{name}", [_.errorTimeout]: "Tempo limite excedido.", [_.errorTitle]: "Opa...", diff --git a/src/Scripts/model/i18n/ru.ts b/src/Scripts/model/i18n/ru.ts index 0124415c..546adaba 100644 --- a/src/Scripts/model/i18n/ru.ts +++ b/src/Scripts/model/i18n/ru.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "No unopened reports available.", [_.errorRetry]: "Повторить", [_.errorSignInMsalExceptionOccurred]: "Непредвиденная ошибка в запросе на вход.", - [_.errorSignInMsalTimeoutExpired]: "Запрос на вход был отменен, так как время ожидания истекло до завершения операции", [_.errorTemplateAlreadyExists]: "Еще один шаблон с тем же путем уже существует:
{name}", [_.errorTimeout]: "Истекло время ожидания запроса", [_.errorTitle]: "Ой...", diff --git a/src/Scripts/model/i18n/tr.ts b/src/Scripts/model/i18n/tr.ts index 458b14ac..07520a88 100644 --- a/src/Scripts/model/i18n/tr.ts +++ b/src/Scripts/model/i18n/tr.ts @@ -158,7 +158,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Açılmamış rapor yok.", [_.errorRetry]: "Yeniden Dene", [_.errorSignInMsalExceptionOccurred]: "Oturum açma isteğinde beklenmeyen hata.", - [_.errorSignInMsalTimeoutExpired]: "İşlem tamamlanmadan önce zaman aşımı süresi sona erdiği için oturum açma isteği iptal edildi.", [_.errorTemplateAlreadyExists]: "Aynı yola sahip başka bir şablon zaten var:
{name}", [_.errorTimeout]: "İstek zaman aşımı.", [_.errorTitle]: "Hata...", diff --git a/src/Scripts/model/i18n/uk.ts b/src/Scripts/model/i18n/uk.ts index a72be4ae..1c60eb8d 100644 --- a/src/Scripts/model/i18n/uk.ts +++ b/src/Scripts/model/i18n/uk.ts @@ -157,7 +157,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "Невідкритих звітів немає.", [_.errorRetry]: "Спробувати повторно", [_.errorSignInMsalExceptionOccurred]: "Неочікувана помилка в запиті на вхід.", - [_.errorSignInMsalTimeoutExpired]: "Запит на вхід було скасовано, оскільки час очікування закінчився до завершення операції.", [_.errorTemplateAlreadyExists]: "Інший шаблон з таким самим шляхом/назвою вже існує:
{name}", [_.errorTimeout]: "Запросити перерву", [_.errorTitle]: "Упс...", diff --git a/src/Scripts/model/i18n/zh.ts b/src/Scripts/model/i18n/zh.ts index 766bc09f..6fade7f1 100644 --- a/src/Scripts/model/i18n/zh.ts +++ b/src/Scripts/model/i18n/zh.ts @@ -156,7 +156,6 @@ const locale: Locale = { [_.errorReportsEmptyListing]: "没找到未打开的报告", [_.errorRetry]: "再试一次", [_.errorSignInMsalExceptionOccurred]: "登录请求出现异常", - [_.errorSignInMsalTimeoutExpired]: "操作超时, 登录请求被取消", [_.errorTemplateAlreadyExists]: "另一个具有相同路径的模板已经存在:
{name}", [_.errorTimeout]: "请求超时", [_.errorTitle]: "Whoops...", diff --git a/src/Scripts/model/strings.ts b/src/Scripts/model/strings.ts index d5e661da..e78f2929 100644 --- a/src/Scripts/model/strings.ts +++ b/src/Scripts/model/strings.ts @@ -149,7 +149,6 @@ export enum strings { errorReportsEmptyListing, errorRetry, errorSignInMsalExceptionOccurred, - errorSignInMsalTimeoutExpired, errorTemplateAlreadyExists, errorTimeout, errorTitle, diff --git a/src/Scripts/view/powerbi-signin.ts b/src/Scripts/view/powerbi-signin.ts index e2eac72f..2f79f774 100644 --- a/src/Scripts/view/powerbi-signin.ts +++ b/src/Scripts/view/powerbi-signin.ts @@ -146,7 +146,7 @@ export class PowerBISignin extends Dialog { onAction(action: string, resolve: any, reject: any) { if (action == "signin") { auth.signIn(this.data) - .then(() => { + .then(() => { super.onAction(action, resolve, reject); }) .catch(ignore => { @@ -154,6 +154,9 @@ export class PowerBISignin extends Dialog { this.element.classList.remove("wait"); }); } else { + if (action == "cancel" && this.element.classList.contains("wait")) + host.apiAbortByAction("auth/SignIn"); + super.onAction(action, resolve, reject); } } diff --git a/src/Services/AuthenticationService.cs b/src/Services/AuthenticationService.cs index 49d0a304..a22d7a50 100644 --- a/src/Services/AuthenticationService.cs +++ b/src/Services/AuthenticationService.cs @@ -1,6 +1,5 @@ namespace Sqlbi.Bravo.Services { - using Sqlbi.Bravo.Infrastructure; using Sqlbi.Bravo.Infrastructure.PowerBI.Cloud; using Sqlbi.Bravo.Infrastructure.PowerBI.Cloud.Authentication; using Sqlbi.Bravo.Infrastructure.PowerBI.Cloud.Configuration; @@ -30,26 +29,12 @@ public async Task> GetEnvironmentsAsync(string e public async Task EnsureSignedInAsync(CancellationToken cancellationToken) { - try - { - return await _cloudAuthenticationService.EnsureSignedInAsync(cancellationToken); - } - catch (OperationCanceledException) - { - throw new BravoException(BravoProblem.SignInMsalTimeoutExpired); - } + return await _cloudAuthenticationService.EnsureSignedInAsync(cancellationToken); } public async Task SignInAsync(string email, CloudEnvironment environment, CancellationToken cancellationToken) { - try - { - return await _cloudAuthenticationService.SignInAsync(email, environment, cancellationToken); - } - catch (OperationCanceledException) - { - throw new BravoException(BravoProblem.SignInMsalTimeoutExpired); - } + return await _cloudAuthenticationService.SignInAsync(email, environment, cancellationToken); } public async Task SignOutAsync(CancellationToken cancellationToken)