Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion localization/l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,6 @@
"comment": ["{0} is the error message"]
},
"No Microsoft Entra account can be found for removal.": "No Microsoft Entra account can be found for removal.",
"Azure token cache cleared successfully.": "Azure token cache cleared successfully.",
"Cannot connect due to expired tokens. Please re-authenticate and try again.": "Cannot connect due to expired tokens. Please re-authenticate and try again.",
"Microsoft Entra Id": "Microsoft Entra Id",
"Choose a Microsoft Entra tenant": "Choose a Microsoft Entra tenant",
Expand Down Expand Up @@ -1154,6 +1153,7 @@
"comment": ["{0} is the account display name", "{1} is the tenant id"]
},
"Clear cache and refresh token": "Clear cache and refresh token",
"Clear token cache": "Clear token cache",
"No workspaces found. Please change Fabric account or tenant to view available workspaces.": "No workspaces found. Please change Fabric account or tenant to view available workspaces.",
"Add Firewall Rule to {0}/{0} is the server name": {
"message": "Add Firewall Rule to {0}",
Expand Down Expand Up @@ -1252,6 +1252,7 @@
"message": "{0} invalid Entra accounts have been removed; you may need to run `MS SQL: Clear Microsoft Entra account token cache` and log in again.",
"comment": ["{0} is the number of invalid accounts that have been removed"]
},
"Entra token cache cleared successfully.": "Entra token cache cleared successfully.",
"Database Name": "Database Name",
"Enter Database Name": "Enter Database Name",
"Database Name is required": "Database Name is required",
Expand Down
9 changes: 6 additions & 3 deletions localization/xliff/vscode-mssql.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,6 @@
<trans-unit id="++CODE++314afcc6e23d362133e764e1ebfacabe4d330308b528392570949a17270248b9">
<source xml:lang="en">Azure sign in failed.</source>
</trans-unit>
<trans-unit id="++CODE++3d1ae152f7c95ef16327aafe54bc82e4565547c236299ef06d54a8db5980c24f">
<source xml:lang="en">Azure token cache cleared successfully.</source>
</trans-unit>
<trans-unit id="++CODE++f71dfcecebed757febe54c711e436e17521c71da90d4c5cc61ef6717918173a4">
<source xml:lang="en">Azure: Sign In</source>
</trans-unit>
Expand Down Expand Up @@ -553,6 +550,9 @@
<trans-unit id="++CODE++21f5ea19572773c428e8375b3d63058ad4f04aea83df347deb633f9ddad9a643">
<source xml:lang="en">Clear permissions for all extensions to access your connections</source>
</trans-unit>
<trans-unit id="++CODE++524ed5b794acd857648e76bead9db5ba131ebcb17f3a92d98ece51db61e65dbf">
<source xml:lang="en">Clear token cache</source>
</trans-unit>
<trans-unit id="++CODE++4e0d71f8a0b3fdc5cdaba4028072ad8cf788bac47864232a1988ac9453453a36">
<source xml:lang="en">Click to cancel loading summary</source>
</trans-unit>
Expand Down Expand Up @@ -1192,6 +1192,9 @@
<trans-unit id="++CODE++0a6b9ae24f863f5d06e0151c62f16b9327fdac6783807dc163e953559aa8287f">
<source xml:lang="en">Enter profile name</source>
</trans-unit>
<trans-unit id="++CODE++d59e5e8f8a4bb3b14eb8af194553158e5dffd648ad462eeafb2f03589da5a8eb">
<source xml:lang="en">Entra token cache cleared successfully.</source>
</trans-unit>
<trans-unit id="++CODE++f939ae3d30c69e332a36892f70d401d457e6993f056b8d0af3fe3d736821f5a1">
<source xml:lang="en">Equals</source>
</trans-unit>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"@dagrejs/dagre": "^1.1.4",
"@eslint/compat": "^1.1.0",
"@fluentui-contrib/react-data-grid-react-window": "^1.2.0",
"@fluentui/react-components": "^9.64.0",
"@fluentui/react-components": "^9.72.2",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@monaco-editor/react": "^4.6.0",
"@playwright/test": "^1.45.0",
Expand Down
6 changes: 2 additions & 4 deletions src/azure/msal/msalAzureController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,7 @@ export class MsalAzureController extends AzureController {
}

await this._cachePluginProvider.unlinkMsalCache();

// Delete Encryption Keys
await this._cachePluginProvider.clearCacheEncryptionKeys();
await this._cachePluginProvider.clearCacheEncryptionKeys(); // Delete Encryption Keys
}

/**
Expand Down Expand Up @@ -293,7 +291,7 @@ export class MsalAzureController extends AzureController {
account?.displayInfo?.displayName,
tenantId,
),
LocalizedConstants.ConnectionDialog.ClearCacheAndRefreshToken,
LocalizedConstants.ConnectionDialog.clearCacheAndRefreshToken,
LocalizedConstants.Common.cancel,
);
if (response === LocalizedConstants.msgYes) {
Expand Down
6 changes: 3 additions & 3 deletions src/connectionconfig/azureHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ export async function promptForAzureSubscriptionFilter(
const auth = await VsCodeAzureHelper.signIn();

if (!auth) {
state.formError = l10n.t("Azure sign in failed.");
state.formMessage = { message: l10n.t("Azure sign in failed.") };
return false;
}

Expand All @@ -269,8 +269,8 @@ export async function promptForAzureSubscriptionFilter(

return true;
} catch (error) {
state.formError = l10n.t("Error loading Azure subscriptions.");
logger.error(state.formError + "\n" + getErrorMessage(error));
state.formMessage = { message: l10n.t("Error loading Azure subscriptions.") };
logger.error(state.formMessage.message + "\n" + getErrorMessage(error));
return false;
}
}
Expand Down
79 changes: 54 additions & 25 deletions src/connectionconfig/connectionDialogWebviewController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
Fabric as LocFabric,
refreshTokenLabel,
} from "../constants/locConstants";
import * as LocAll from "../constants/locConstants";
import {
getAccounts,
getTenants,
Expand Down Expand Up @@ -71,6 +72,7 @@ import { FormWebviewController } from "../forms/formWebviewController";
import { ConnectionCredentials } from "../models/connectionCredentials";
import { Deferred } from "../protocol";
import { configSelectedAzureSubscriptions } from "../constants/constants";
import * as AzureConstants from "../azure/constants";
import { AddFirewallRuleState } from "../sharedInterfaces/addFirewallRule";
import * as Utils from "../models/utils";
import {
Expand All @@ -94,6 +96,7 @@ import {
import { getCloudId } from "../azure/providerSettings";

const FABRIC_WORKSPACE_AUTOLOAD_LIMIT = 10;
export const CLEAR_TOKEN_CACHE = "clearTokenCache";

export class ConnectionDialogWebviewController extends FormWebviewController<
IConnectionDialogProfile,
Expand Down Expand Up @@ -255,7 +258,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
this.registerReducer("setConnectionInputType", async (state, payload) => {
this.state.selectedInputMode = payload.inputMode;
await this.updateItemVisibility();
state.formError = "";
state.formMessage = undefined;
this.updateState();

if (state.selectedInputMode === ConnectionInputMode.AzureBrowse) {
Expand Down Expand Up @@ -356,7 +359,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
);
state.dialog = undefined;
} catch (err) {
state.formError = getErrorMessage(err);
state.formMessage = { message: getErrorMessage(err) };
state.dialog = undefined;

sendErrorEvent(
Expand Down Expand Up @@ -392,7 +395,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
);
if (typeof createConnectionGroupResult === "string") {
// If the result is a string, it means there was an error creating the group
state.formError = createConnectionGroupResult;
state.formMessage = { message: createConnectionGroupResult };
} else {
// If the result is an IConnectionGroup, it means the group was created successfully
state.connectionProfile.groupId = createConnectionGroupResult.id;
Expand All @@ -419,7 +422,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
});

this.registerReducer("closeMessage", async (state) => {
state.formError = undefined;
state.formMessage = undefined;
return state;
});

Expand All @@ -429,7 +432,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
await this.loadAllAzureServers(state);
}
} catch (err) {
this.state.formError = getErrorMessage(err);
this.state.formMessage = { message: getErrorMessage(err) };

sendErrorEvent(
TelemetryViews.ConnectionDialog,
Expand Down Expand Up @@ -528,7 +531,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
(state.dialog as ConnectionStringDialogProps).connectionStringError =
errorMessage;
} else {
state.formError = errorMessage;
state.formMessage = { message: errorMessage };
}

sendErrorEvent(
Expand All @@ -547,7 +550,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
this.registerReducer("openConnectionStringDialog", async (state) => {
if (state.selectedInputMode !== ConnectionInputMode.Parameters) {
state.selectedInputMode = ConnectionInputMode.Parameters;
state.formError = undefined;
state.formMessage = undefined;
this.updateState(state);
}

Expand Down Expand Up @@ -623,7 +626,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
if (payload.browseTarget === ConnectionInputMode.AzureBrowse) {
if (state.selectedInputMode !== ConnectionInputMode.AzureBrowse) {
state.selectedInputMode = ConnectionInputMode.AzureBrowse;
state.formError = undefined;
state.formMessage = undefined;
this.updateState(state);
}
}
Expand All @@ -641,7 +644,9 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
await VsCodeAzureHelper.signIn(true /* forceSignInPrompt */);
} catch (error) {
this.logger.error("Error signing into Azure: " + getErrorMessage(error));
state.formError = LocAzure.errorSigningIntoAzure(getErrorMessage(error));
state.formMessage = {
message: LocAzure.errorSigningIntoAzure(getErrorMessage(error)),
};

return state;
}
Expand Down Expand Up @@ -744,6 +749,18 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
return state;
});

this.registerReducer("messageButtonClicked", async (state, payload) => {
if (payload.buttonId === CLEAR_TOKEN_CACHE) {
this._mainController.connectionManager.azureController.clearTokenCache();
this.vscodeWrapper.showInformationMessage(LocAll.Accounts.clearedEntraTokenCache);
this.state.formMessage = undefined;
} else {
this.logger.error(`Unknown message button clicked: ${payload.buttonId}`);
}

return state;
});

this.onRequest(GetSqlAnalyticsEndpointUriFromFabricRequest.type, async (payload) => {
const getUriActivity = startActivity(
TelemetryViews.ConnectionDialog,
Expand Down Expand Up @@ -983,7 +1000,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
const tempConnectionUri = Utils.generateGuid();
const result = await this._mainController.connectionManager.connect(
tempConnectionUri,
cleanedConnection as any,
cleanedConnection,
false, // Connect should not handle errors, as we want to handle them here
);

Expand All @@ -994,9 +1011,17 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
return await this.handleConnectionErrorCodes(connectionInfo, state);
}
} catch (error) {
this.state.formError = getErrorMessage(error);
this.state.formMessage = { message: getErrorMessage(error) };
this.state.connectionStatus = ApiStatus.Error;

if (
getErrorMessage(error).includes(AzureConstants.multiple_matching_tokens_error)
) {
this.state.formMessage.buttons = [
{ id: CLEAR_TOKEN_CACHE, label: Loc.clearTokenCache },
];
}

sendErrorEvent(
TelemetryViews.ConnectionDialog,
TelemetryActions.CreateConnection,
Expand Down Expand Up @@ -1084,7 +1109,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
UserSurvey.getInstance().promptUserForNPSFeedback();
} catch (error) {
this.state.connectionStatus = ApiStatus.Error;
this.state.formError = getErrorMessage(error);
this.state.formMessage = { message: getErrorMessage(error) };

sendErrorEvent(
TelemetryViews.ConnectionDialog,
Expand Down Expand Up @@ -1178,7 +1203,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
return state;
} else if (errorType === SqlConnectionErrorType.PasswordExpired) {
this.state.connectionStatus = ApiStatus.Error;
this.state.formError = `${result.errorNumber}: ${result.errorMessage}`;
this.state.formMessage = { message: `${result.errorNumber}: ${result.errorMessage}` };
this.state.dialog = {
type: "changePassword",
props: {
Expand All @@ -1188,7 +1213,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
} as ChangePasswordDialogProps;
return state;
} else {
this.state.formError = result.errorMessage;
this.state.formMessage = { message: result.errorMessage };
this.state.connectionStatus = ApiStatus.Error;

sendActionEvent(TelemetryViews.ConnectionDialog, TelemetryActions.CreateConnection, {
Expand Down Expand Up @@ -1432,7 +1457,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
state.azureTenants = [];
this.updateState(state);

state.formError = "";
state.formMessage = undefined;
state.azureAccounts = (await VsCodeAzureHelper.getAccounts()).map((a) => {
return {
id: a.id,
Expand All @@ -1452,7 +1477,9 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
try {
auth = await VsCodeAzureHelper.signIn();
} catch (error) {
state.formError = LocAzure.errorSigningIntoAzure(getErrorMessage(error));
state.formMessage = {
message: LocAzure.errorSigningIntoAzure(getErrorMessage(error)),
};
return undefined;
}

Expand Down Expand Up @@ -1505,9 +1532,9 @@ export class ConnectionDialogWebviewController extends FormWebviewController<

return tenantSubMap;
} catch (error) {
state.formError = l10n.t("Error loading Azure subscriptions.");
state.formMessage = { message: l10n.t("Error loading Azure subscriptions.") };
state.loadingAzureSubscriptionsStatus = ApiStatus.Error;
this.logger.error(state.formError + "\n" + getErrorMessage(error));
this.logger.error(state.formMessage + "\n" + getErrorMessage(error));
telemActivity?.endFailed(error, false);
return undefined;
}
Expand All @@ -1526,9 +1553,11 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
}

if (tenantSubMap.size === 0) {
state.formError = l10n.t(
"No subscriptions available. Adjust your subscription filters to try again.",
);
state.formMessage = {
message: l10n.t(
"No subscriptions available. Adjust your subscription filters to try again.",
),
};
} else {
state.loadingAzureServersStatus = ApiStatus.Loading;
state.azureServers = [];
Expand All @@ -1554,9 +1583,9 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
return;
}
} catch (error) {
state.formError = l10n.t("Error loading Azure databases.");
state.formMessage = { message: l10n.t("Error loading Azure databases.") };
state.loadingAzureServersStatus = ApiStatus.Error;
this.logger.error(state.formError + os.EOL + getErrorMessage(error));
this.logger.error(state.formMessage.message + os.EOL + getErrorMessage(error));

endActivity.endFailed(
error,
Expand Down Expand Up @@ -1693,7 +1722,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
);
}
} catch (err) {
state.formError = getErrorMessage(err);
state.formMessage = { message: getErrorMessage(err) };

loadWorkspacesActivity.endFailed(
new Error("Failure while getting Fabric workspaces"),
Expand Down Expand Up @@ -1811,7 +1840,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
//#region Miscellanous helpers

private clearFormError() {
this.state.formError = "";
this.state.formMessage = undefined;
for (const component of this.getActiveFormComponents(this.state).map(
(x) => this.state.formComponents[x],
)) {
Expand Down
5 changes: 3 additions & 2 deletions src/constants/locConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ export function accountRemovalFailed(error: string) {
export let noAzureAccountForRemoval = l10n.t(
"No Microsoft Entra account can be found for removal.",
);
export let clearedAzureTokenCache = l10n.t("Azure token cache cleared successfully.");
export let cannotConnect = l10n.t(
"Cannot connect due to expired tokens. Please re-authenticate and try again.",
);
Expand Down Expand Up @@ -719,7 +718,8 @@ export class ConnectionDialog {
comment: ["{0} is the account display name", "{1} is the tenant id"],
});
}
public static ClearCacheAndRefreshToken = l10n.t("Clear cache and refresh token");
public static clearCacheAndRefreshToken = l10n.t("Clear cache and refresh token");
public static clearTokenCache = l10n.t("Clear token cache");

public static noWorkspacesFound = l10n.t(
"No workspaces found. Please change Fabric account or tenant to view available workspaces.",
Expand Down Expand Up @@ -938,6 +938,7 @@ export class Accounts {
comment: ["{0} is the number of invalid accounts that have been removed"],
});
};
public static clearedEntraTokenCache = l10n.t("Entra token cache cleared successfully.");
}

export class FabricProvisioning {
Expand Down
Loading