Improve connection string login feedback

This commit is contained in:
Asier Isayas
2026-08-27 11:03:49 -04:00
parent ea056bfaeb
commit 5fe07c2523
2 changed files with 113 additions and 35 deletions
@@ -80,6 +80,63 @@ it("hides the connection string link when feature.disableConnectionStringLogin i
updateUserContext({ features: oldFeatures });
});
it("rejects an unrecognized connection string before token exchange", async () => {
render(
<ConnectExplorer
{...{
login: jest.fn(),
setEncryptedToken: jest.fn(),
setAuthType: jest.fn(),
connectionString: "not-a-valid-connection-string",
setConnectionString: jest.fn(),
setAccountMetadata: jest.fn(),
}}
/>,
);
fireEvent.click(screen.getByText("Connect to your account with connection string"));
fireEvent.click(screen.getByDisplayValue("Connect"));
expect(
await screen.findByText(
"We couldn't recognize this connection string. Verify that it is a valid Azure Cosmos DB connection string and try again.",
),
).toBeInTheDocument();
expect(mockIsAccountRestricted).not.toHaveBeenCalled();
expect(mockFetchEncryptedToken).not.toHaveBeenCalled();
});
it("shows that a connection is in progress", async () => {
let finishRestrictionCheck: (restricted: boolean) => void = () => undefined;
mockIsAccountRestricted.mockImplementation(
() =>
new Promise((resolve) => {
finishRestrictionCheck = resolve;
}),
);
render(
<ConnectExplorer
{...{
login: jest.fn(),
setEncryptedToken: jest.fn(),
setAuthType: jest.fn(),
connectionString: "AccountEndpoint=https://test.documents.azure.com:443/;AccountKey=some-key;",
setConnectionString: jest.fn(),
setAccountMetadata: jest.fn(),
}}
/>,
);
fireEvent.click(screen.getByText("Connect to your account with connection string"));
fireEvent.click(screen.getByDisplayValue("Connect"));
const connectButton = screen.getByDisplayValue("Connecting...");
expect(connectButton).toBeDisabled();
expect(connectButton.closest("form")).toHaveAttribute("aria-busy", "true");
finishRestrictionCheck(false);
expect(await screen.findByDisplayValue("Connect")).toBeEnabled();
});
it("shows the error when the Portal Backend rejects the connection string", async () => {
// Mongo and Cassandra are the APIs that still exchange the connection string for an encrypted token.
const mongoConnectionString = "mongodb://test:key@test.documents.azure.com:10255";
@@ -32,6 +32,7 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
const [isFormVisible, { setTrue: showForm }] = useBoolean(false);
const [errorMessage, setErrorMessage] = React.useState("");
const [isBlockedByFirewall, setIsBlockedByFirewall] = React.useState(false);
const [isConnecting, setIsConnecting] = React.useState(false);
const enableConnectionStringLogin = !userContext.features.disableConnectionStringLogin;
return (
@@ -45,10 +46,30 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
{isFormVisible && enableConnectionStringLogin ? (
<form
id="connectWithConnectionString"
aria-busy={isConnecting}
onSubmit={async (event) => {
event.preventDefault();
if (isConnecting) {
return;
}
setErrorMessage("");
setIsBlockedByFirewall(false);
setIsConnecting(true);
try {
if (isResourceTokenConnectionString(connectionString)) {
setAuthType(AuthType.ResourceToken);
return;
}
const metadata = parseConnectionString(connectionString);
if (!metadata) {
setErrorMessage(
"We couldn't recognize this connection string. Verify that it is a valid Azure Cosmos DB connection string and try again.",
);
return;
}
try {
if (await isAccountRestrictedForConnectionStringLogin(connectionString)) {
@@ -58,19 +79,11 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
return;
}
} catch (error) {
setErrorMessage(getErrorMessage(error));
setErrorMessage(getErrorMessage(error as Error));
return;
}
if (isResourceTokenConnectionString(connectionString)) {
setAuthType(AuthType.ResourceToken);
return;
}
const metadata = parseConnectionString(connectionString);
if (metadata && isDirectConnectionStringLoginApi(metadata.apiKind)) {
// SQL, Table, and Gremlin sign data-plane requests client-side with the account key, so
// we skip the Portal Backend proxy and use the metadata parsed from the connection string.
if (isDirectConnectionStringLoginApi(metadata.apiKind)) {
setAccountMetadata(metadata);
setAuthType(AuthType.ConnectionString);
return;
@@ -94,6 +107,9 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
// to allowlist those services.
setIsBlockedByFirewall((error as Response).status === HttpStatusCodes.Forbidden);
}
} finally {
setIsConnecting(false);
}
}}
>
<p className="connectExplorerContent connectStringText">Connect to your account with connection string</p>
@@ -129,7 +145,12 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
</FluentProvider>
)}
<p className="connectExplorerContent">
<input className="filterbtnstyle" type="submit" value="Connect" />
<input
className="filterbtnstyle"
type="submit"
value={isConnecting ? "Connecting..." : "Connect"}
disabled={isConnecting}
/>
</p>
<p className="switchConnectTypeText" onClick={login}>
Sign In with Azure Account