From 91d9e27049edf1f80b1c0f250e5b4a2aeadb83db Mon Sep 17 00:00:00 2001 From: Laurent Nguyen Date: Thu, 14 Mar 2024 20:56:26 +0000 Subject: [PATCH 1/6] Turn off fetching authorization token (#1766) --- src/Common/CosmosClient.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/Common/CosmosClient.ts b/src/Common/CosmosClient.ts index f35efbd00..f75c47454 100644 --- a/src/Common/CosmosClient.ts +++ b/src/Common/CosmosClient.ts @@ -1,7 +1,6 @@ import * as Cosmos from "@azure/cosmos"; -import { sendCachedDataMessage } from "Common/MessageHandler"; import { getAuthorizationTokenUsingResourceTokens } from "Common/getAuthorizationTokenUsingResourceTokens"; -import { AuthorizationToken, MessageTypes } from "Contracts/MessageTypes"; +import { AuthorizationToken } from "Contracts/MessageTypes"; import { checkDatabaseResourceTokensValidity } from "Platform/Fabric/FabricUtil"; import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility"; import { AuthType } from "../AuthType"; @@ -51,15 +50,23 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => { case Cosmos.ResourceType.offer: case Cosmos.ResourceType.user: case Cosmos.ResourceType.permission: - // User master tokens - const authorizationToken = await sendCachedDataMessage( - MessageTypes.GetAuthorizationToken, - [requestInfo], - userContext.fabricContext.connectionId, - ); - console.log("Response from Fabric: ", authorizationToken); - headers[HttpHeaders.msDate] = authorizationToken.XDate; - return decodeURIComponent(authorizationToken.PrimaryReadWriteToken); + // For now, these operations aren't used, so fetching the authorization token is commented out. + // This provider must return a real token to pass validation by the client, so we return the cached resource token + // (which is a valid token, but won't work for these operations). + const resourceTokens2 = userContext.fabricContext.databaseConnectionInfo.resourceTokens; + return getAuthorizationTokenUsingResourceTokens(resourceTokens2, requestInfo.path, requestInfo.resourceId); + + /* ************** TODO: Uncomment this code if we need to support these operations ************** + // User master tokens + const authorizationToken = await sendCachedDataMessage( + MessageTypes.GetAuthorizationToken, + [requestInfo], + userContext.fabricContext.connectionId, + ); + console.log("Response from Fabric: ", authorizationToken); + headers[HttpHeaders.msDate] = authorizationToken.XDate; + return decodeURIComponent(authorizationToken.PrimaryReadWriteToken); + ***********************************************************************************************/ } } From ac22e88d9cbeca1212615ee7b5719e9f72a94d66 Mon Sep 17 00:00:00 2001 From: sunghyunkang1111 <114709653+sunghyunkang1111@users.noreply.github.com> Date: Mon, 18 Mar 2024 12:15:24 -0500 Subject: [PATCH 2/6] rebranding of inline copilot (#1767) * rebranding of inline copilot * rebranding of inline copilot * rebranding of inline copilot * fix styling --- .../Modal/QueryCopilotFeedbackModal.tsx | 9 +- .../QueryCopilotFeedbackModal.test.tsx.snap | 105 +++ .../QueryCopilot/QueryCopilotPromptbar.tsx | 694 ++++++++++-------- 3 files changed, 497 insertions(+), 311 deletions(-) diff --git a/src/Explorer/QueryCopilot/Modal/QueryCopilotFeedbackModal.tsx b/src/Explorer/QueryCopilot/Modal/QueryCopilotFeedbackModal.tsx index d8d68f4cc..c96f8d179 100644 --- a/src/Explorer/QueryCopilot/Modal/QueryCopilotFeedbackModal.tsx +++ b/src/Explorer/QueryCopilot/Modal/QueryCopilotFeedbackModal.tsx @@ -49,7 +49,7 @@ export const QueryCopilotFeedbackModal = ({ }; return ( - +
@@ -68,9 +68,14 @@ export const QueryCopilotFeedbackModal = ({ rows={3} /> diff --git a/src/Explorer/QueryCopilot/Modal/__snapshots__/QueryCopilotFeedbackModal.test.tsx.snap b/src/Explorer/QueryCopilot/Modal/__snapshots__/QueryCopilotFeedbackModal.test.tsx.snap index dc7f4c96f..356b86977 100644 --- a/src/Explorer/QueryCopilot/Modal/__snapshots__/QueryCopilotFeedbackModal.test.tsx.snap +++ b/src/Explorer/QueryCopilot/Modal/__snapshots__/QueryCopilotFeedbackModal.test.tsx.snap @@ -3,6 +3,14 @@ exports[`Query Copilot Feedback Modal snapshot test shoud render and match snapshot 1`] = ` = ({ const generateSQLQueryResponse: GenerateSQLQueryResponse = await response?.json(); if (response.ok) { if (generateSQLQueryResponse?.sql !== "N/A") { - let query = `-- **Prompt:** ${userPrompt}\r\n`; - if (generateSQLQueryResponse.explanation) { - query += `-- **Explanation of query:** ${generateSQLQueryResponse.explanation}\r\n`; - } - query += generateSQLQueryResponse.sql; - setQuery(query); + let currentGeneratedQuery = `-- **Prompt:** ${userPrompt}\r\n`; + currentGeneratedQuery += generateSQLQueryResponse.sql; + const lastQuery = generatedQuery && query ? `${query}\r\n` : ""; + setQuery(`${lastQuery}${currentGeneratedQuery}`); setGeneratedQuery(generateSQLQueryResponse.sql); setGeneratedQueryComments(generateSQLQueryResponse.explanation); setShowFeedbackBar(true); @@ -310,12 +307,388 @@ export const QueryCopilotPromptbar: React.FC = ({ return ( - - Copilot - Copilot + + + + { + inputEdited.current = true; + setShowSamplePrompts(true); + }} + onKeyDown={(e) => { + if (e.key === "Enter" && userPrompt) { + inputEdited.current = true; + startGenerateQueryProcess(); + } + }} + style={{ lineHeight: 30 }} + styles={{ + root: { width: "100%" }, + suffix: { + background: "none", + padding: 0, + }, + fieldGroup: { + borderRadius: 4, + borderColor: "#D1D1D1", + "::after": { + border: "inherit", + borderWidth: 2, + borderBottomColor: "#464FEB", + borderRadius: 4, + }, + }, + }} + disabled={isGeneratingQuery} + autoComplete="off" + placeholder="Ask a question in natural language and we’ll generate the query for you." + aria-labelledby="copilot-textfield-label" + onRenderSuffix={() => { + return ( + startGenerateQueryProcess()} + aria-label="Send" + /> + ); + }} + /> + {showPromptTeachingBubble && copilotTeachingBubbleVisible && ( + toggleCopilotTeachingBubbleVisible(false)} + hasSmallHeadline={true} + headline="Write a prompt" + > + Write a prompt here and Copilot will generate the query for you. You can also choose from our{" "} + { + setShowSamplePrompts(true); + toggleCopilotTeachingBubbleVisible(false); + }} + style={{ color: "white", fontWeight: 600 }} + > + sample prompts + {" "} + or write your own query + + )} + {showSamplePrompts && ( + setShowSamplePrompts(false)} + directionalHintFixed={true} + directionalHint={DirectionalHint.bottomLeftEdge} + alignTargetEdge={true} + gapSpace={4} + > + + {filteredHistories?.length > 0 && ( + + + Recent + + {filteredHistories.map((history, i) => ( + { + setUserPrompt(history); + setShowSamplePrompts(false); + inputEdited.current = true; + }} + onRenderIcon={() => } + styles={promptStyles} + > + {history} + + ))} + + )} + {filteredSuggestedPrompts?.length > 0 && ( + + + Suggested Prompts + + {filteredSuggestedPrompts.map((prompt) => ( + { + setUserPrompt(prompt.text); + setShowSamplePrompts(false); + inputEdited.current = true; + }} + onRenderIcon={() => } + styles={promptStyles} + > + {prompt.text} + + ))} + + )} + {(filteredHistories?.length > 0 || filteredSuggestedPrompts?.length > 0) && ( + + + + Learn about{" "} + + writing effective prompts + + + + )} + + + )} + + {!isGeneratingQuery && ( + + {!showFeedbackBar && ( + + AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "} + + Read preview terms + + {showErrorMessageBar && ( + + {errorMessage ? errorMessage : "We ran into an error and were not able to execute query."} + + )} + {showInvalidQueryMessageBar && ( + + We were unable to generate a query based upon the prompt provided. Please modify the prompt and + try again. For examples of how to write a good prompt, please read + + this article. + {" "} + Our content guidelines can be found + + here. + + + )} + + )} + {showFeedbackBar && ( + + {userContext.feedbackPolicies?.policyAllowFeedback && ( + + Provide feedback + {showCallout && !hideFeedbackModalForLikedQueries && ( + { + setShowCallout(false); + SubmitFeedback({ + params: { + generatedQuery: generatedQuery, + likeQuery: likeQuery, + description: "", + userPrompt: userPrompt, + }, + explorer, + databaseId, + containerId, + mode: isSampleCopilotActive ? "Sample" : "User", + }); + }} + directionalHint={DirectionalHint.topCenter} + > + + Thank you. Need to give{" "} + { + setShowCallout(false); + openFeedbackModal(generatedQuery, true, userPrompt); + }} + > + more feedback? + + + + )} + { + setShowCallout(!likeQuery); + setLikeQuery(!likeQuery); + if (likeQuery === true) { + document.getElementById("likeStatus").innerHTML = "Unpressed"; + } + if (likeQuery === false) { + document.getElementById("likeStatus").innerHTML = "Liked"; + } + if (dislikeQuery) { + setDislikeQuery(!dislikeQuery); + } + }} + /> + { + let toggleStatusValue = "Unpressed"; + if (!dislikeQuery) { + openFeedbackModal(generatedQuery, false, userPrompt); + setLikeQuery(false); + toggleStatusValue = "Disliked"; + } + setDislikeQuery(!dislikeQuery); + setShowCallout(false); + document.getElementById("likeStatus").innerHTML = toggleStatusValue; + }} + /> + + + + )} + + Copy code + + { + setShowDeletePopup(true); + }} + iconProps={{ iconName: "Delete" }} + style={{ fontSize: 12, transition: "background-color 0.3s ease", height: "100%" }} + styles={{ + root: { + backgroundColor: "inherit", + }, + }} + > + Clear editor + + + )} + + )} + {isGeneratingQuery && ( + + )} + { @@ -323,307 +696,10 @@ export const QueryCopilotPromptbar: React.FC = ({ clearFeedback(); resetMessageStates(); }} - styles={{ - root: { - marginLeft: "auto !important", - }, - }} ariaLabel="Close" title="Close copilot" /> - - { - inputEdited.current = true; - setShowSamplePrompts(true); - }} - onKeyDown={(e) => { - if (e.key === "Enter" && userPrompt) { - inputEdited.current = true; - startGenerateQueryProcess(); - } - }} - style={{ lineHeight: 30 }} - styles={{ root: { width: "95%" }, fieldGroup: { borderRadius: 6 } }} - disabled={isGeneratingQuery} - autoComplete="off" - placeholder="Ask a question in natural language and we’ll generate the query for you." - aria-labelledby="copilot-textfield-label" - /> - {showPromptTeachingBubble && copilotTeachingBubbleVisible && ( - toggleCopilotTeachingBubbleVisible(false)} - hasSmallHeadline={true} - headline="Write a prompt" - > - Write a prompt here and Copilot will generate the query for you. You can also choose from our{" "} - { - setShowSamplePrompts(true); - toggleCopilotTeachingBubbleVisible(false); - }} - style={{ color: "white", fontWeight: 600 }} - > - sample prompts - {" "} - or write your own query - - )} - startGenerateQueryProcess()} - aria-label="Send" - /> -
- {isGeneratingQuery && } -
- {showSamplePrompts && ( - setShowSamplePrompts(false)} - directionalHintFixed={true} - directionalHint={DirectionalHint.bottomLeftEdge} - alignTargetEdge={true} - gapSpace={4} - > - - {filteredHistories?.length > 0 && ( - - - Recent - - {filteredHistories.map((history, i) => ( - { - setUserPrompt(history); - setShowSamplePrompts(false); - inputEdited.current = true; - }} - onRenderIcon={() => } - styles={promptStyles} - > - {history} - - ))} - - )} - {filteredSuggestedPrompts?.length > 0 && ( - - - Suggested Prompts - - {filteredSuggestedPrompts.map((prompt) => ( - { - setUserPrompt(prompt.text); - setShowSamplePrompts(false); - inputEdited.current = true; - }} - onRenderIcon={() => } - styles={promptStyles} - > - {prompt.text} - - ))} - - )} - {(filteredHistories?.length > 0 || filteredSuggestedPrompts?.length > 0) && ( - - - - Learn about{" "} - - writing effective prompts - - - - )} - - - )} -
- - - - AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "} - - Read preview terms - - {showErrorMessageBar && ( - - {errorMessage ? errorMessage : "We ran into an error and were not able to execute query."} - - )} - {showInvalidQueryMessageBar && ( - - We were unable to generate a query based upon the prompt provided. Please modify the prompt and try again. - For examples of how to write a good prompt, please read - - this article. - {" "} - Our content guidelines can be found - - here. - - - )} - - - - {showFeedbackBar && ( - - {userContext.feedbackPolicies?.policyAllowFeedback && ( - - Provide feedback on the query generated - {showCallout && !hideFeedbackModalForLikedQueries && ( - { - setShowCallout(false); - SubmitFeedback({ - params: { - generatedQuery: generatedQuery, - likeQuery: likeQuery, - description: "", - userPrompt: userPrompt, - }, - explorer, - databaseId, - containerId, - mode: isSampleCopilotActive ? "Sample" : "User", - }); - }} - directionalHint={DirectionalHint.topCenter} - > - - Thank you. Need to give{" "} - { - setShowCallout(false); - openFeedbackModal(generatedQuery, true, userPrompt); - }} - > - more feedback? - - - - )} - { - setShowCallout(!likeQuery); - setLikeQuery(!likeQuery); - if (likeQuery === true) { - document.getElementById("likeStatus").innerHTML = "Unpressed"; - } - if (likeQuery === false) { - document.getElementById("likeStatus").innerHTML = "Liked"; - } - if (dislikeQuery) { - setDislikeQuery(!dislikeQuery); - } - }} - /> - { - let toggleStatusValue = "Unpressed"; - if (!dislikeQuery) { - openFeedbackModal(generatedQuery, false, userPrompt); - setLikeQuery(false); - toggleStatusValue = "Disliked"; - } - setDislikeQuery(!dislikeQuery); - setShowCallout(false); - document.getElementById("likeStatus").innerHTML = toggleStatusValue; - }} - /> - - - - )} - - Copy query - - { - setShowDeletePopup(true); - }} - iconProps={{ iconName: "Delete" }} - style={{ margin: "0 10px", backgroundColor: "#FFF8F0", transition: "background-color 0.3s ease" }} - > - Delete query - - - )} {isSamplePromptsOpen && } {query !== "" && query.trim().length !== 0 && ( Date: Mon, 18 Mar 2024 10:49:33 -0700 Subject: [PATCH 3/6] Fix API endpoint for CassandraProxy query API (#1769) --- src/Common/Constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 804c8adea..041ecf132 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -139,7 +139,7 @@ export class CassandraBackend { export class CassandraProxyAPIs { public static readonly createOrDeleteApi: string = "api/cassandra/createordelete"; public static readonly connectionStringCreateOrDeleteApi: string = "api/connectionstring/cassandra/createordelete"; - public static readonly queryApi: string = "api/cassandra/postquery"; + public static readonly queryApi: string = "api/cassandra"; public static readonly connectionStringQueryApi: string = "api/connectionstring/cassandra"; public static readonly keysApi: string = "api/cassandra/keys"; public static readonly connectionStringKeysApi: string = "api/connectionstring/cassandra/keys"; From a524138ac98ff7f24f0d7dc874e446ec5c62f013 Mon Sep 17 00:00:00 2001 From: Vsevolod Kukol Date: Wed, 20 Mar 2024 00:28:24 +0100 Subject: [PATCH 4/6] Don't show the new Home button in Fabric (#1774) as the whole Home tab feature is not supported there. --- .../Menus/CommandBar/CommandBarComponentButtonFactory.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx index f55bef9d2..c37ae41fb 100644 --- a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx +++ b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx @@ -58,10 +58,10 @@ export function createStaticCommandBarButtons( } }; - const homeBtn = createHomeButton(); - buttons.push(homeBtn); - if (configContext.platform !== Platform.Fabric) { + const homeBtn = createHomeButton(); + buttons.push(homeBtn); + const newCollectionBtn = createNewCollectionGroup(container); buttons.push(newCollectionBtn); if (userContext.apiType !== "Tables" && userContext.apiType !== "Cassandra") { From da2e874ae6b5a6dab613a306add65f297250f69a Mon Sep 17 00:00:00 2001 From: sunghyunkang1111 <114709653+sunghyunkang1111@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:23:42 -0500 Subject: [PATCH 5/6] Fix bugs on data transfer and bring back query explanation and remove query prompt from editor (#1777) * Fix minor issues * add back preview tag * bring back query explanation and remove prompt in editor --- src/Common/dataAccess/dataTransfers.ts | 11 +++++++++-- .../PartitionKeyComponent.tsx | 14 +++++++------- src/Explorer/Controls/Settings/SettingsUtils.tsx | 2 +- .../__snapshots__/SettingsComponent.test.tsx.snap | 2 +- .../ChangePartitionKeyPane.tsx | 2 ++ .../QueryCopilot/QueryCopilotPromptbar.tsx | 6 ++++-- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/Common/dataAccess/dataTransfers.ts b/src/Common/dataAccess/dataTransfers.ts index 138257c15..e639f9965 100644 --- a/src/Common/dataAccess/dataTransfers.ts +++ b/src/Common/dataAccess/dataTransfers.ts @@ -122,14 +122,21 @@ const pollDataTransferJobOperation = async ( updateDataTransferJob(body); - if (status === "Cancelled" || status === "Failed" || status === "Faulted") { + if (status === "Cancelled") { + removeFromPolling(jobName); + clearMessage && clearMessage(); + const cancelMessage = `Data transfer job ${jobName} cancelled`; + NotificationConsoleUtils.logConsoleError(cancelMessage); + throw new AbortError(cancelMessage); + } + if (status === "Failed" || status === "Faulted") { removeFromPolling(jobName); const errorMessage = body?.properties?.error ? JSON.stringify(body?.properties?.error) : "Operation could not be completed"; const error = new Error(errorMessage); clearMessage && clearMessage(); - NotificationConsoleUtils.logConsoleError(`Data transfer job ${jobName} Failed`); + NotificationConsoleUtils.logConsoleError(`Data transfer job ${jobName} failed: ${errorMessage}`); throw new AbortError(error); } if (status === "Completed") { diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/PartitionKeyComponent.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/PartitionKeyComponent.tsx index 2efe7fb92..1930808a7 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/PartitionKeyComponent.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/PartitionKeyComponent.tsx @@ -136,15 +136,15 @@ export const PartitionKeyComponent: React.FC = ({ da }; const getPercentageComplete = () => { + const jobStatus = portalDataTransferJob?.properties?.status; + const isCompleted = jobStatus === "Completed"; + if (isCompleted) { + return 1; + } const processedCount = portalDataTransferJob?.properties?.processedCount; const totalCount = portalDataTransferJob?.properties?.totalCount; - const jobStatus = portalDataTransferJob?.properties?.status; - const isCancelled = jobStatus === "Cancelled"; - const isCompleted = jobStatus === "Completed"; - if (totalCount <= 0 && !isCompleted) { - return isCancelled ? 0 : null; - } - return isCompleted ? 1 : processedCount / totalCount; + const isJobInProgress = isCurrentJobInProgress(portalDataTransferJob); + return isJobInProgress ? (totalCount > 0 ? processedCount / totalCount : null) : 0; }; return ( diff --git a/src/Explorer/Controls/Settings/SettingsUtils.tsx b/src/Explorer/Controls/Settings/SettingsUtils.tsx index c53974b88..869ae323a 100644 --- a/src/Explorer/Controls/Settings/SettingsUtils.tsx +++ b/src/Explorer/Controls/Settings/SettingsUtils.tsx @@ -149,7 +149,7 @@ export const getTabTitle = (tab: SettingsV2TabTypes): string => { case SettingsV2TabTypes.IndexingPolicyTab: return "Indexing Policy"; case SettingsV2TabTypes.PartitionKeyTab: - return "Partition Keys"; + return "Partition Keys (preview)"; case SettingsV2TabTypes.ComputedPropertiesTab: return "Computed Properties (preview)"; default: diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index 3b9f76195..ab7abac11 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -207,7 +207,7 @@ exports[`SettingsComponent renders 1`] = ` /> = ({
{createNewContainer ? ( + All configurations except for unique keys will be copied from the source container diff --git a/src/Explorer/QueryCopilot/QueryCopilotPromptbar.tsx b/src/Explorer/QueryCopilot/QueryCopilotPromptbar.tsx index 412b17051..6aaebc926 100644 --- a/src/Explorer/QueryCopilot/QueryCopilotPromptbar.tsx +++ b/src/Explorer/QueryCopilot/QueryCopilotPromptbar.tsx @@ -214,8 +214,10 @@ export const QueryCopilotPromptbar: React.FC = ({ const generateSQLQueryResponse: GenerateSQLQueryResponse = await response?.json(); if (response.ok) { if (generateSQLQueryResponse?.sql !== "N/A") { - let currentGeneratedQuery = `-- **Prompt:** ${userPrompt}\r\n`; - currentGeneratedQuery += generateSQLQueryResponse.sql; + const queryExplanation = `-- **Explanation of query:** ${ + generateSQLQueryResponse.explanation ? generateSQLQueryResponse.explanation : "N/A" + }\r\n`; + const currentGeneratedQuery = queryExplanation + generateSQLQueryResponse.sql; const lastQuery = generatedQuery && query ? `${query}\r\n` : ""; setQuery(`${lastQuery}${currentGeneratedQuery}`); setGeneratedQuery(generateSQLQueryResponse.sql); From e09930d9d02e18fa6315e2d3c7f171a46809112c Mon Sep 17 00:00:00 2001 From: Asier Isayas Date: Fri, 22 Mar 2024 13:18:02 -0400 Subject: [PATCH 6/6] Support Token API in new Portal Backend (#1773) * added support for generate token * fix checks * fix checks * deactivate mongo proxy * fix tests * remove mongo proxy from mpac * change endpoints to prod * npm run format * add await --------- Co-authored-by: Asier Isayas --- src/Common/Constants.ts | 44 ++++++++++++------- src/Common/MongoProxyClient.ts | 3 +- src/ConfigContext.ts | 12 ++++- .../Hosted/Components/ConnectExplorer.tsx | 20 ++++++++- src/Utils/EndpointUtils.ts | 15 ++++++- 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 041ecf132..fe9c2672d 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -124,6 +124,34 @@ export enum MongoBackendEndpointType { remote, } +export enum BackendApi { + GenerateToken, +} + +export class PortalBackendEndpoints { + public static readonly Development: string = "https://localhost:7235"; + public static readonly Mpac: string = "https://cdb-ms-mpac-pbe.cosmos.azure.com"; + public static readonly Prod: string = "https://cdb-ms-prod-pbe.cosmos.azure.com"; + public static readonly Fairfax: string = "https://cdb-ff-prod-pbe.cosmos.azure.us"; + public static readonly Mooncake: string = "https://cdb-mc-prod-pbe.cosmos.azure.cn"; +} + +export class MongoProxyEndpoints { + public static readonly Development: string = "https://localhost:7238"; + public static readonly Mpac: string = "https://cdb-ms-mpac-mp.cosmos.azure.com"; + public static readonly Prod: string = "https://cdb-ms-prod-mp.cosmos.azure.com"; + public static readonly Fairfax: string = "https://cdb-ff-prod-mp.cosmos.azure.us"; + public static readonly Mooncake: string = "https://cdb-mc-prod-mp.cosmos.azure.cn"; +} + +export class CassandraProxyEndpoints { + public static readonly Development: string = "https://localhost:7240"; + public static readonly Mpac: string = "https://cdb-ms-mpac-cp.cosmos.azure.com"; + public static readonly Prod: string = "https://cdb-ms-prod-cp.cosmos.azure.com"; + public static readonly Fairfax: string = "https://cdb-ff-prod-cp.cosmos.azure.us"; + public static readonly Mooncake: string = "https://cdb-mc-prod-cp.cosmos.azure.cn"; +} + //TODO: Remove this when new backend is migrated over export class CassandraBackend { public static readonly createOrDeleteApi: string = "api/cassandra/createordelete"; @@ -446,22 +474,6 @@ export class JunoEndpoints { public static readonly Stage = "https://tools-staging.cosmos.azure.com"; } -export class MongoProxyEndpoints { - public static readonly Development: string = "https://localhost:7238"; - public static readonly Mpac: string = "https://cdb-ms-mpac-mp.cosmos.azure.com"; - public static readonly Prod: string = "https://cdb-ms-prod-mp.cosmos.azure.com"; - public static readonly Fairfax: string = "https://cdb-ff-prod-mp.cosmos.azure.us"; - public static readonly Mooncake: string = "https://cdb-mc-prod-mp.cosmos.azure.cn"; -} - -export class CassandraProxyEndpoints { - public static readonly Development: string = "https://localhost:7240"; - public static readonly Mpac: string = "https://cdb-ms-mpac-cp.cosmos.azure.com"; - public static readonly Prod: string = "https://cdb-ms-prod-cp.cosmos.azure.com"; - public static readonly Fairfax: string = "https://cdb-ff-prod-cp.cosmos.azure.us"; - public static readonly Mooncake: string = "https://cdb-mc-prod-cp.cosmos.azure.cn"; -} - export class PriorityLevel { public static readonly High = "high"; public static readonly Low = "low"; diff --git a/src/Common/MongoProxyClient.ts b/src/Common/MongoProxyClient.ts index 357ce1f50..e37b0eff5 100644 --- a/src/Common/MongoProxyClient.ts +++ b/src/Common/MongoProxyClient.ts @@ -690,6 +690,7 @@ export function getARMCreateCollectionEndpoint(params: DataModels.MongoParameter } function useMongoProxyEndpoint(api: string): boolean { + const activeMongoProxyEndpoints: string[] = [MongoProxyEndpoints.Development]; let canAccessMongoProxy: boolean = userContext.databaseAccount.properties.publicNetworkAccess === "Enabled"; if (userContext.databaseAccount.properties.ipRules?.length > 0) { canAccessMongoProxy = canAccessMongoProxy && configContext.MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED; @@ -698,6 +699,6 @@ function useMongoProxyEndpoint(api: string): boolean { return ( canAccessMongoProxy && configContext.NEW_MONGO_APIS?.includes(api) && - [MongoProxyEndpoints.Development, MongoProxyEndpoints.Mpac].includes(configContext.MONGO_PROXY_ENDPOINT) + activeMongoProxyEndpoints.includes(configContext.MONGO_PROXY_ENDPOINT) ); } diff --git a/src/ConfigContext.ts b/src/ConfigContext.ts index f02fa260d..e3350c7f6 100644 --- a/src/ConfigContext.ts +++ b/src/ConfigContext.ts @@ -1,4 +1,10 @@ -import { CassandraProxyEndpoints, JunoEndpoints, MongoProxyEndpoints } from "Common/Constants"; +import { + BackendApi, + CassandraProxyEndpoints, + JunoEndpoints, + MongoProxyEndpoints, + PortalBackendEndpoints, +} from "Common/Constants"; import { allowedAadEndpoints, allowedArcadiaEndpoints, @@ -39,6 +45,8 @@ export interface ConfigContext { ARCADIA_ENDPOINT: string; ARCADIA_LIVY_ENDPOINT_DNS_ZONE: string; BACKEND_ENDPOINT?: string; + PORTAL_BACKEND_ENDPOINT?: string; + NEW_BACKEND_APIS?: BackendApi[]; MONGO_BACKEND_ENDPOINT?: string; MONGO_PROXY_ENDPOINT?: string; MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED?: boolean; @@ -90,6 +98,8 @@ let configContext: Readonly = { GITHUB_TEST_ENV_CLIENT_ID: "b63fc8cbf87fd3c6e2eb", // Registered OAuth app: https://github.com/organizations/AzureCosmosDBNotebooks/settings/applications/1777772 JUNO_ENDPOINT: JunoEndpoints.Prod, BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com", + PORTAL_BACKEND_ENDPOINT: PortalBackendEndpoints.Prod, + NEW_BACKEND_APIS: [BackendApi.GenerateToken], MONGO_PROXY_ENDPOINT: MongoProxyEndpoints.Prod, NEW_MONGO_APIS: [ // "resourcelist", diff --git a/src/Platform/Hosted/Components/ConnectExplorer.tsx b/src/Platform/Hosted/Components/ConnectExplorer.tsx index dd291f279..6b33d021b 100644 --- a/src/Platform/Hosted/Components/ConnectExplorer.tsx +++ b/src/Platform/Hosted/Components/ConnectExplorer.tsx @@ -1,10 +1,11 @@ import { useBoolean } from "@fluentui/react-hooks"; import { userContext } from "UserContext"; +import { usePortalBackendEndpoint } from "Utils/EndpointUtils"; import * as React from "react"; import ConnectImage from "../../../../images/HdeConnectCosmosDB.svg"; import ErrorImage from "../../../../images/error.svg"; import { AuthType } from "../../../AuthType"; -import { HttpHeaders } from "../../../Common/Constants"; +import { BackendApi, HttpHeaders } from "../../../Common/Constants"; import { configContext } from "../../../ConfigContext"; import { GenerateTokenResponse } from "../../../Contracts/DataModels"; import { isResourceTokenConnectionString } from "../Helpers/ResourceTokenUtils"; @@ -18,6 +19,23 @@ interface Props { } export const fetchEncryptedToken = async (connectionString: string): Promise => { + if (!usePortalBackendEndpoint(BackendApi.GenerateToken)) { + return await fetchEncryptedToken_ToBeDeprecated(connectionString); + } + + const headers = new Headers(); + headers.append(HttpHeaders.connectionString, connectionString); + const url = configContext.PORTAL_BACKEND_ENDPOINT + "/api/connectionstring/token/generatetoken"; + const response = await fetch(url, { headers, method: "POST" }); + if (!response.ok) { + throw response; + } + + const encryptedTokenResponse: string = await response.json(); + return decodeURIComponent(encryptedTokenResponse); +}; + +export const fetchEncryptedToken_ToBeDeprecated = async (connectionString: string): Promise => { const headers = new Headers(); headers.append(HttpHeaders.connectionString, connectionString); const url = configContext.BACKEND_ENDPOINT + "/api/guest/tokens/generateToken"; diff --git a/src/Utils/EndpointUtils.ts b/src/Utils/EndpointUtils.ts index ee01f7f9a..4962c285b 100644 --- a/src/Utils/EndpointUtils.ts +++ b/src/Utils/EndpointUtils.ts @@ -1,4 +1,11 @@ -import { CassandraProxyEndpoints, JunoEndpoints, MongoProxyEndpoints } from "Common/Constants"; +import { + BackendApi, + CassandraProxyEndpoints, + JunoEndpoints, + MongoProxyEndpoints, + PortalBackendEndpoints, +} from "Common/Constants"; +import { configContext } from "ConfigContext"; import * as Logger from "../Common/Logger"; export function validateEndpoint( @@ -137,3 +144,9 @@ export const allowedJunoOrigins: ReadonlyArray = [ ]; export const allowedNotebookServerUrls: ReadonlyArray = []; + +export function usePortalBackendEndpoint(backendApi: BackendApi): boolean { + const activePortalBackendEndpoints: string[] = [PortalBackendEndpoints.Development]; + const activeBackendApi: boolean = configContext.NEW_BACKEND_APIS?.includes(backendApi) || false; + return activeBackendApi && activePortalBackendEndpoints.includes(configContext.PORTAL_BACKEND_ENDPOINT as string); +}