Compare commits

..

5 Commits

Author SHA1 Message Date
Sung-Hyun Kang
7cf0eb511a Add componentDidMount for initial render 2024-06-17 14:19:23 -05:00
Sung-Hyun Kang
f7b7d135df merge conflict 2024-06-17 13:40:18 -05:00
Sung-Hyun Kang
1ab6bf3d81 Remove dependency on previous prop of deletion id 2024-06-17 13:23:22 -05:00
Sung-Hyun Kang
ac8dbbc0d2 sample db handling 2024-06-17 12:30:28 -05:00
Sung-Hyun Kang
edfd6cfc30 handle sampledb error handling to load the data explorer 2024-06-12 22:41:35 -05:00
20 changed files with 95 additions and 151 deletions

View File

@@ -133,7 +133,6 @@ export enum MongoBackendEndpointType {
export class BackendApi { export class BackendApi {
public static readonly GenerateToken: string = "GenerateToken"; public static readonly GenerateToken: string = "GenerateToken";
public static readonly PortalSettings: string = "PortalSettings"; public static readonly PortalSettings: string = "PortalSettings";
public static readonly AccountRestrictions: string = "AccountRestrictions";
} }
export class PortalBackendEndpoints { export class PortalBackendEndpoints {

View File

@@ -1,7 +1,6 @@
import { FabricMessageTypes } from "Contracts/FabricMessageTypes"; import { FabricMessageTypes } from "Contracts/FabricMessageTypes";
import Q from "q"; import Q from "q";
import * as _ from "underscore"; import * as _ from "underscore";
import * as Logger from "../Common/Logger";
import { MessageTypes } from "../Contracts/ExplorerContracts"; import { MessageTypes } from "../Contracts/ExplorerContracts";
import { getDataExplorerWindow } from "../Utils/WindowUtils"; import { getDataExplorerWindow } from "../Utils/WindowUtils";
import * as Constants from "./Constants"; import * as Constants from "./Constants";
@@ -97,18 +96,10 @@ const _sendMessage = (message: any): void => {
const portalChildWindow = getDataExplorerWindow(window) || window; const portalChildWindow = getDataExplorerWindow(window) || window;
if (portalChildWindow === window) { if (portalChildWindow === window) {
// Current window is a child of portal, send message to portal window // Current window is a child of portal, send message to portal window
if (portalChildWindow.document.referrer) { portalChildWindow.parent.postMessage(message, portalChildWindow.document.referrer || "*");
portalChildWindow.parent.postMessage(message, portalChildWindow.document.referrer);
} else {
Logger.logError("Iframe failed to send message to portal", "MessageHandler");
}
} else { } else {
// Current window is not a child of portal, send message to the child window instead (which is data explorer) // Current window is not a child of portal, send message to the child window instead (which is data explorer)
if (portalChildWindow.location.origin) { portalChildWindow.postMessage(message, portalChildWindow.location.origin || "*");
portalChildWindow.postMessage(message, portalChildWindow.location.origin);
} else {
Logger.logError("Iframe failed to send message to data explorer", "MessageHandler");
}
} }
} }
}; };

View File

@@ -2,6 +2,7 @@ import { CosmosClient } from "@azure/cosmos";
import { sampleDataClient } from "Common/SampleDataClient"; import { sampleDataClient } from "Common/SampleDataClient";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
import { client } from "../CosmosClient"; import { client } from "../CosmosClient";
import { handleError } from "../ErrorHandlingUtils"; import { handleError } from "../ErrorHandlingUtils";
@@ -30,6 +31,7 @@ export async function readCollectionInternal(
collectionId: string, collectionId: string,
): Promise<DataModels.Collection> { ): Promise<DataModels.Collection> {
let collection: DataModels.Collection; let collection: DataModels.Collection;
const clearMessage = logConsoleProgress(`Querying container ${collectionId}`);
try { try {
const response = await cosmosClient.database(databaseId).container(collectionId).read(); const response = await cosmosClient.database(databaseId).container(collectionId).read();
collection = response.resource as DataModels.Collection; collection = response.resource as DataModels.Collection;
@@ -37,5 +39,6 @@ export async function readCollectionInternal(
handleError(error, "ReadCollection", `Error while querying container ${collectionId}`); handleError(error, "ReadCollection", `Error while querying container ${collectionId}`);
throw error; throw error;
} }
clearMessage();
return collection; return collection;
} }

View File

@@ -109,14 +109,14 @@ let configContext: Readonly<ConfigContext> = {
PORTAL_BACKEND_ENDPOINT: PortalBackendEndpoints.Prod, PORTAL_BACKEND_ENDPOINT: PortalBackendEndpoints.Prod,
MONGO_PROXY_ENDPOINT: MongoProxyEndpoints.Prod, MONGO_PROXY_ENDPOINT: MongoProxyEndpoints.Prod,
NEW_MONGO_APIS: [ NEW_MONGO_APIS: [
// "resourcelist", "resourcelist",
// "queryDocuments", "queryDocuments",
// "createDocument", "createDocument",
// "readDocument", "readDocument",
// "updateDocument", "updateDocument",
// "deleteDocument", "deleteDocument",
// "createCollectionWithProxy", "createCollectionWithProxy",
// "legacyMongoShell", "legacyMongoShell",
], ],
MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED: false, MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED: false,
CASSANDRA_PROXY_ENDPOINT: CassandraProxyEndpoints.Prod, CASSANDRA_PROXY_ENDPOINT: CassandraProxyEndpoints.Prod,

View File

@@ -20,7 +20,7 @@
outline-offset: 2px; outline-offset: 2px;
} }
.outlineNone { .outlineNone{
outline: none !important; outline: none !important;
} }
@@ -28,8 +28,3 @@
.deleteQuery:focus::after { .deleteQuery:focus::after {
outline: none !important; outline: none !important;
} }
.highlightedButtonStyles {
outline: 1px dashed back;
background-color: #ebebeb;
}

View File

@@ -1158,7 +1158,7 @@ export default class Explorer {
public async refreshSampleData(): Promise<void> { public async refreshSampleData(): Promise<void> {
try { try {
if (!userContext.sampleDataConnectionInfo) { if (!userContext.sampleDataConnectionInfo || useDatabases.getState().sampleDataResourceTokenCollection) {
return; return;
} }
const collection: DataModels.Collection = await readSampleCollection(); const collection: DataModels.Collection = await readSampleCollection();

View File

@@ -162,7 +162,7 @@ export const addRootChildToGraph = (
* @param value * @param value
*/ */
export const escapeDoubleQuotes = (value: string): string => { export const escapeDoubleQuotes = (value: string): string => {
return value === undefined ? value : value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); return value === undefined ? value : value.replace(/"/g, '\\"');
}; };
/** /**
@@ -186,5 +186,5 @@ export const getQuotedPropValue = (ip: ViewModels.InputPropertyValue): string =>
* @param value * @param value
*/ */
export const escapeSingleQuotes = (value: string): string => { export const escapeSingleQuotes = (value: string): string => {
return value === undefined ? value : value.replace(/\\/g, "\\\\").replace(/'/g, "\\'"); return value === undefined ? value : value.replace(/'/g, "\\'");
}; };

View File

@@ -57,6 +57,10 @@ export class NotificationConsoleComponent extends React.Component<
this.prevHeaderStatus = undefined; this.prevHeaderStatus = undefined;
} }
public componentDidMount() {
this.componentDidUpdate(this.props, this.state);
}
public componentDidUpdate( public componentDidUpdate(
prevProps: NotificationConsoleComponentProps, prevProps: NotificationConsoleComponentProps,
prevState: NotificationConsoleComponentState, prevState: NotificationConsoleComponentState,
@@ -265,20 +269,29 @@ export class NotificationConsoleComponent extends React.Component<
}; };
private updateConsoleData = (prevProps: NotificationConsoleComponentProps): void => { private updateConsoleData = (prevProps: NotificationConsoleComponentProps): void => {
let updatedConsoleData: ConsoleData[] = [...this.state.allConsoleData];
let refresh = false;
if (!this.areConsoleDataEqual(this.props.consoleData, prevProps.consoleData)) { if (!this.areConsoleDataEqual(this.props.consoleData, prevProps.consoleData)) {
this.setState({ allConsoleData: [this.props.consoleData, ...this.state.allConsoleData] }); updatedConsoleData = [this.props.consoleData, ...updatedConsoleData];
refresh = true;
} }
if ( if (this.props.inProgressConsoleDataIdToBeDeleted) {
this.props.inProgressConsoleDataIdToBeDeleted && const hasMatchingItem = updatedConsoleData.some(
prevProps.inProgressConsoleDataIdToBeDeleted !== this.props.inProgressConsoleDataIdToBeDeleted
) {
const allConsoleData = this.state.allConsoleData.filter(
(data: ConsoleData) => (data: ConsoleData) =>
!(data.type === ConsoleDataType.InProgress && data.id === this.props.inProgressConsoleDataIdToBeDeleted), data.type === ConsoleDataType.InProgress && data.id === this.props.inProgressConsoleDataIdToBeDeleted,
); );
this.setState({ allConsoleData });
if (hasMatchingItem) {
updatedConsoleData = updatedConsoleData.filter(
(data: ConsoleData) =>
!(data.type === ConsoleDataType.InProgress && data.id === this.props.inProgressConsoleDataIdToBeDeleted),
);
refresh = true;
}
} }
refresh && this.setState({ allConsoleData: updatedConsoleData });
}; };
private areConsoleDataEqual = (currentData: ConsoleData, prevData: ConsoleData): boolean => { private areConsoleDataEqual = (currentData: ConsoleData, prevData: ConsoleData): boolean => {

View File

@@ -576,7 +576,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</TooltipHost> </TooltipHost>
</Stack> </Stack>
<Text variant="small">{this.getPartitionKeySubtext()}</Text> <Text variant="small" aria-label="pkDescription">
{this.getPartitionKeySubtext()}
</Text>
<input <input
type="text" type="text"

View File

@@ -264,7 +264,7 @@ export const ChangePartitionKeyPane: React.FC<ChangePartitionKeyPaneProps> = ({
</TooltipHost> </TooltipHost>
</Stack> </Stack>
<Text variant="small"> <Text variant="small" aria-label="pkDescription">
{getPartitionKeySubtext(userContext.features.partitionKeyDefault, userContext.apiType)} {getPartitionKeySubtext(userContext.features.partitionKeyDefault, userContext.apiType)}
</Text> </Text>

View File

@@ -223,6 +223,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
</StyledTooltipHostBase> </StyledTooltipHostBase>
</Stack> </Stack>
<Text <Text
aria-label="pkDescription"
variant="small" variant="small"
/> />
<input <input

View File

@@ -34,13 +34,12 @@ import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/Shared/
import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Action } from "Shared/Telemetry/TelemetryConstants";
import { userContext } from "UserContext"; import { userContext } from "UserContext";
import { useQueryCopilot } from "hooks/useQueryCopilot"; import { useQueryCopilot } from "hooks/useQueryCopilot";
import React, { useCallback, useRef, useState } from "react"; import React, { useRef, useState } from "react";
import HintIcon from "../../../images/Hint.svg"; import HintIcon from "../../../images/Hint.svg";
import RecentIcon from "../../../images/Recent.svg"; import RecentIcon from "../../../images/Recent.svg";
import errorIcon from "../../../images/close-black.svg"; import errorIcon from "../../../images/close-black.svg";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { useTabs } from "../../hooks/useTabs"; import { useTabs } from "../../hooks/useTabs";
import "../Controls/ThroughputInput/ThroughputInput.less";
import { useCopilotStore } from "../QueryCopilot/QueryCopilotContext"; import { useCopilotStore } from "../QueryCopilot/QueryCopilotContext";
import { useSelectedNode } from "../useSelectedNode"; import { useSelectedNode } from "../useSelectedNode";
@@ -109,7 +108,7 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
setErrorMessage, setErrorMessage,
errorMessage, errorMessage,
} = useCopilotStore(); } = useCopilotStore();
const [focusedIndex, setFocusedIndex] = useState(-1);
const sampleProps: SamplePromptsProps = { const sampleProps: SamplePromptsProps = {
isSamplePromptsOpen: isSamplePromptsOpen, isSamplePromptsOpen: isSamplePromptsOpen,
setIsSamplePromptsOpen: setIsSamplePromptsOpen, setIsSamplePromptsOpen: setIsSamplePromptsOpen,
@@ -302,41 +301,6 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
return "Content is updated"; return "Content is updated";
} }
}; };
const openSamplePrompts = () => {
inputEdited.current = true;
setShowSamplePrompts(true);
};
const suggestionHistory = filteredHistories.concat(filteredSuggestedPrompts.map((item) => item.text));
const handleKeyDown: React.KeyboardEventHandler = (e) => {
const { key } = e;
if (key === "ArrowDown") {
setFocusedIndex((focusedIndex + 1) % suggestionHistory.length);
}
if (key === "ArrowUp") {
setFocusedIndex((focusedIndex + suggestionHistory.length - 1) % suggestionHistory.length);
}
if (key === "Enter") {
e.preventDefault();
handleSelection(focusedIndex);
}
};
const handleSelection = (selectedIndex: number) => {
const selectedItem = suggestionHistory[selectedIndex];
if (!selectedItem) {
return resetSearchComplete();
} else {
handlePromptSet(selectedItem);
}
};
const resetSearchComplete = useCallback(() => {
setFocusedIndex(-1);
setShowSamplePrompts(false);
}, []);
const handlePromptSet = (promptText: string) => {
inputEdited.current = true;
setUserPrompt(promptText);
};
React.useEffect(() => { React.useEffect(() => {
useTabs.getState().setIsQueryErrorThrown(false); useTabs.getState().setIsQueryErrorThrown(false);
@@ -367,13 +331,23 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
id="naturalLanguageInput" id="naturalLanguageInput"
value={userPrompt} value={userPrompt}
onChange={handleUserPromptChange} onChange={handleUserPromptChange}
onClick={openSamplePrompts} onClick={() => {
onFocus={() => setShowSamplePrompts(true)} inputEdited.current = true;
onKeyDown={handleKeyDown} setShowSamplePrompts(true);
}}
onKeyDown={(e) => {
if (e.key === "Enter" && userPrompt) {
inputEdited.current = true;
startGenerateQueryProcess();
}
}}
style={{ lineHeight: 30 }} style={{ lineHeight: 30 }}
styles={{ styles={{
root: { width: "100%" }, root: { width: "100%" },
suffix: { background: "none", padding: 0 }, suffix: {
background: "none",
padding: 0,
},
fieldGroup: { fieldGroup: {
borderRadius: 4, borderRadius: 4,
borderColor: "#D1D1D1", borderColor: "#D1D1D1",
@@ -386,8 +360,7 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
}, },
}} }}
disabled={isGeneratingQuery} disabled={isGeneratingQuery}
autoComplete="list" autoComplete="off"
aria-expanded={showSamplePrompts}
placeholder="Ask a question in natural language and well generate the query for you." placeholder="Ask a question in natural language and well generate the query for you."
aria-labelledby="copilot-textfield-label" aria-labelledby="copilot-textfield-label"
onRenderSuffix={() => { onRenderSuffix={() => {
@@ -396,10 +369,7 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
iconProps={{ iconName: "Send" }} iconProps={{ iconName: "Send" }}
disabled={isGeneratingQuery || !userPrompt.trim()} disabled={isGeneratingQuery || !userPrompt.trim()}
style={{ background: "none" }} style={{ background: "none" }}
onClick={() => { onClick={() => startGenerateQueryProcess()}
startGenerateQueryProcess();
setShowSamplePrompts(false);
}}
aria-label="Send" aria-label="Send"
/> />
); );
@@ -464,7 +434,6 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
}} }}
onRenderIcon={() => <Image src={RecentIcon} styles={{ root: { overflow: "unset" } }} />} onRenderIcon={() => <Image src={RecentIcon} styles={{ root: { overflow: "unset" } }} />}
styles={promptStyles} styles={promptStyles}
className={focusedIndex === i ? "highlightedButtonStyles" : "buttonstyles"}
> >
{history} {history}
</DefaultButton> </DefaultButton>
@@ -485,7 +454,7 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
> >
Suggested Prompts Suggested Prompts
</Text> </Text>
{filteredSuggestedPrompts.map((prompt, index) => ( {filteredSuggestedPrompts.map((prompt) => (
<DefaultButton <DefaultButton
key={prompt.id} key={prompt.id}
onClick={() => { onClick={() => {
@@ -495,7 +464,6 @@ export const QueryCopilotPromptbar: React.FC<QueryCopilotPromptProps> = ({
}} }}
onRenderIcon={() => <Image src={HintIcon} />} onRenderIcon={() => <Image src={HintIcon} />}
styles={promptStyles} styles={promptStyles}
className={focusedIndex === filteredHistories.length + index ? "highlightedButtonStyles" : ""}
> >
{prompt.text} {prompt.text}
</DefaultButton> </DefaultButton>

View File

@@ -363,24 +363,18 @@ export class CassandraAPIDataClient extends TableDataClient {
entitiesToDelete: Entities.ITableEntity[], entitiesToDelete: Entities.ITableEntity[],
): Promise<any> { ): Promise<any> {
const query = `DELETE FROM ${collection.databaseId}.${collection.id()} WHERE `; const query = `DELETE FROM ${collection.databaseId}.${collection.id()} WHERE `;
const partitionKeys: CassandraTableKey[] = collection.cassandraKeys.partitionKeys; const partitionKeyProperty = this.getCassandraPartitionKeyProperty(collection);
await Promise.all( await Promise.all(
entitiesToDelete.map(async (currEntityToDelete: Entities.ITableEntity) => { entitiesToDelete.map(async (currEntityToDelete: Entities.ITableEntity) => {
const clearMessage = NotificationConsoleUtils.logConsoleProgress(`Deleting row ${currEntityToDelete.RowKey._}`); const clearMessage = NotificationConsoleUtils.logConsoleProgress(`Deleting row ${currEntityToDelete.RowKey._}`);
const partitionKeyValue = currEntityToDelete[partitionKeyProperty];
const currQuery =
query +
(this.isStringType(partitionKeyValue.$)
? `${partitionKeyProperty} = '${partitionKeyValue._}'`
: `${partitionKeyProperty} = ${partitionKeyValue._}`);
let currQuery = query;
for (let partitionKeyIndex = 0; partitionKeyIndex < partitionKeys.length; partitionKeyIndex++) {
const partitionKey: CassandraTableKey = partitionKeys[partitionKeyIndex];
const partitionKeyValue: Entities.ITableEntityAttribute = currEntityToDelete[partitionKey.property];
currQuery =
currQuery +
(this.isStringType(partitionKeyValue.$)
? `${partitionKey.property} = '${partitionKeyValue._}'`
: `${partitionKey.property} = ${partitionKeyValue._}`);
if (partitionKeyIndex < partitionKeys.length - 1) {
currQuery = `${currQuery} AND `;
}
}
try { try {
await this.queryDocuments(collection, currQuery); await this.queryDocuments(collection, currQuery);
NotificationConsoleUtils.logConsoleInfo(`Successfully deleted row ${currEntityToDelete.RowKey._}`); NotificationConsoleUtils.logConsoleInfo(`Successfully deleted row ${currEntityToDelete.RowKey._}`);

View File

@@ -340,7 +340,7 @@ describe("Documents tab (noSql API)", () => {
isPreferredApiMongoDB: false, isPreferredApiMongoDB: false,
documentIds: [], documentIds: [],
collection: undefined, collection: undefined,
partitionKey: { kind: "Hash", paths: ["/foo"], version: 2 }, partitionKey: undefined,
onLoadStartKey: 0, onLoadStartKey: 0,
tabTitle: "", tabTitle: "",
onExecutionErrorChange: (isExecutionError: boolean): void => { onExecutionErrorChange: (isExecutionError: boolean): void => {

View File

@@ -7,10 +7,7 @@ import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import MongoUtility from "Common/MongoUtility"; import MongoUtility from "Common/MongoUtility";
import { StyleConstants } from "Common/StyleConstants"; import { StyleConstants } from "Common/StyleConstants";
import { createDocument } from "Common/dataAccess/createDocument"; import { createDocument } from "Common/dataAccess/createDocument";
import { import { deleteDocuments as deleteNoSqlDocuments } from "Common/dataAccess/deleteDocument";
deleteDocument as deleteNoSqlDocument,
deleteDocuments as deleteNoSqlDocuments,
} from "Common/dataAccess/deleteDocument";
import { queryDocuments } from "Common/dataAccess/queryDocuments"; import { queryDocuments } from "Common/dataAccess/queryDocuments";
import { readDocument } from "Common/dataAccess/readDocument"; import { readDocument } from "Common/dataAccess/readDocument";
import { updateDocument } from "Common/dataAccess/updateDocument"; import { updateDocument } from "Common/dataAccess/updateDocument";
@@ -827,7 +824,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
}, [initialDocumentContent, selectedDocumentContentBaseline, setSelectedDocumentContent]); }, [initialDocumentContent, selectedDocumentContentBaseline, setSelectedDocumentContent]);
/** /**
* Implementation using bulk delete NoSQL API * Implementation using bulk delete
*/ */
let _deleteDocuments = useCallback( let _deleteDocuments = useCallback(
async (toDeleteDocumentIds: DocumentId[]): Promise<DocumentId[]> => { async (toDeleteDocumentIds: DocumentId[]): Promise<DocumentId[]> => {
@@ -837,14 +834,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
tabTitle, tabTitle,
}); });
setIsExecuting(true); setIsExecuting(true);
return deleteNoSqlDocuments(_collection, toDeleteDocumentIds)
// TODO: Once JS SDK Bug fix for bulk deleting legacy containers (whose systemKey==1) is released:
// Remove the check for systemKey, remove call to deleteNoSqlDocument(). deleteNoSqlDocuments() should always be called.
return (
partitionKey.systemKey
? deleteNoSqlDocument(_collection, toDeleteDocumentIds[0]).then(() => [toDeleteDocumentIds[0]])
: deleteNoSqlDocuments(_collection, toDeleteDocumentIds)
)
.then( .then(
(deletedIds) => { (deletedIds) => {
TelemetryProcessor.traceSuccess( TelemetryProcessor.traceSuccess(
@@ -1810,8 +1800,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
size={tableContainerSizePx} size={tableContainerSizePx}
columnHeaders={columnHeaders} columnHeaders={columnHeaders}
isSelectionDisabled={ isSelectionDisabled={
(partitionKey.systemKey && !isPreferredApiMongoDB) || configContext.platform === Platform.Fabric && userContext.fabricContext?.isReadOnly
(configContext.platform === Platform.Fabric && userContext.fabricContext?.isReadOnly)
} }
/> />
{tableItems.length > 0 && ( {tableItems.length > 0 && (

View File

@@ -1,5 +1,6 @@
import { useMongoProxyEndpoint } from "Common/MongoProxyClient"; import { useMongoProxyEndpoint } from "Common/MongoProxyClient";
import React, { Component } from "react"; import React, { Component } from "react";
import * as Constants from "../../../Common/Constants";
import { configContext } from "../../../ConfigContext"; import { configContext } from "../../../ConfigContext";
import * as ViewModels from "../../../Contracts/ViewModels"; import * as ViewModels from "../../../Contracts/ViewModels";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
@@ -112,6 +113,12 @@ export default class MongoShellTabComponent extends Component<
const resourceId = databaseAccount?.id; const resourceId = databaseAccount?.id;
const accountName = databaseAccount?.name; const accountName = databaseAccount?.name;
const documentEndpoint = databaseAccount?.properties.mongoEndpoint || databaseAccount?.properties.documentEndpoint; const documentEndpoint = databaseAccount?.properties.mongoEndpoint || databaseAccount?.properties.documentEndpoint;
const mongoEndpoint =
documentEndpoint.substr(
Constants.MongoDBAccounts.protocol.length + 3,
documentEndpoint.length -
(Constants.MongoDBAccounts.protocol.length + 2 + Constants.MongoDBAccounts.defaultPort.length),
) + Constants.MongoDBAccounts.defaultPort.toString();
const databaseId = this.props.collection.databaseId; const databaseId = this.props.collection.databaseId;
const collectionId = this.props.collection.id(); const collectionId = this.props.collection.id();
const apiEndpoint = this._useMongoProxyEndpoint const apiEndpoint = this._useMongoProxyEndpoint
@@ -125,7 +132,7 @@ export default class MongoShellTabComponent extends Component<
data: { data: {
resourceId: resourceId, resourceId: resourceId,
accountName: accountName, accountName: accountName,
mongoEndpoint: documentEndpoint, mongoEndpoint: mongoEndpoint,
authorization: authorization, authorization: authorization,
databaseId: databaseId, databaseId: databaseId,
collectionId: collectionId, collectionId: collectionId,

View File

@@ -51,18 +51,13 @@ export const fetchEncryptedToken_ToBeDeprecated = async (connectionString: strin
export const isAccountRestrictedForConnectionStringLogin = async (connectionString: string): Promise<boolean> => { export const isAccountRestrictedForConnectionStringLogin = async (connectionString: string): Promise<boolean> => {
const headers = new Headers(); const headers = new Headers();
headers.append(HttpHeaders.connectionString, connectionString); headers.append(HttpHeaders.connectionString, connectionString);
const url = configContext.BACKEND_ENDPOINT + "/api/guest/accountrestrictions/checkconnectionstringlogin";
const backendEndpoint: string = useNewPortalBackendEndpoint(BackendApi.PortalSettings)
? configContext.PORTAL_BACKEND_ENDPOINT
: configContext.BACKEND_ENDPOINT;
const url = backendEndpoint + "/api/guest/accountrestrictions/checkconnectionstringlogin";
const response = await fetch(url, { headers, method: "POST" }); const response = await fetch(url, { headers, method: "POST" });
if (!response.ok) { if (!response.ok) {
throw response; throw response;
} }
return (await response.text()).toLowerCase() === "true"; return (await response.text()) === "True";
}; };
export const ConnectExplorer: React.FunctionComponent<Props> = ({ export const ConnectExplorer: React.FunctionComponent<Props> = ({

View File

@@ -164,7 +164,6 @@ export function useNewPortalBackendEndpoint(backendApi: string): boolean {
PortalBackendEndpoints.Mpac, PortalBackendEndpoints.Mpac,
PortalBackendEndpoints.Prod, PortalBackendEndpoints.Prod,
], ],
[BackendApi.AccountRestrictions]: [PortalBackendEndpoints.Development, PortalBackendEndpoints.Mpac],
}; };
if (!newBackendApiEnvironmentMap[backendApi] || !configContext.PORTAL_BACKEND_ENDPOINT) { if (!newBackendApiEnvironmentMap[backendApi] || !configContext.PORTAL_BACKEND_ENDPOINT) {

View File

@@ -52,17 +52,11 @@ export async function fetchDatabaseAccountsFromGraph(
const body = { const body = {
query: databaseAccountsQuery, query: databaseAccountsQuery,
subscriptions: [subscriptionId], subscriptions: [subscriptionId],
...(skipToken ...(skipToken && {
? { options: {
options: { $skipToken: skipToken,
$skipToken: skipToken, } as QueryRequestOptions,
} as QueryRequestOptions, }),
}
: {
options: {
$top: 150,
} as QueryRequestOptions,
}),
}; };
const response = await fetch(managementResourceGraphAPIURL, { const response = await fetch(managementResourceGraphAPIURL, {

View File

@@ -51,17 +51,11 @@ export async function fetchSubscriptionsFromGraph(accessToken: string): Promise<
do { do {
const body = { const body = {
query: subscriptionsQuery, query: subscriptionsQuery,
...(skipToken ...(skipToken && {
? { options: {
options: { $skipToken: skipToken,
$skipToken: skipToken, } as QueryRequestOptions,
} as QueryRequestOptions, }),
}
: {
options: {
$top: 150,
} as QueryRequestOptions,
}),
}; };
const response = await fetch(managementResourceGraphAPIURL, { const response = await fetch(managementResourceGraphAPIURL, {