Legacy Mongo Shell Mongo Proxy support (#1802)
* LMS Mongo Proxy support * change stirng to url for get mongo shell url * fix tests * enable feature flag * fixed unit test --------- Co-authored-by: Asier Isayas <aisayas@microsoft.com>
This commit is contained in:
parent
af664326ea
commit
98000a27f0
|
@ -138,7 +138,7 @@ export class PortalBackendEndpoints {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MongoProxyEndpoints {
|
export class MongoProxyEndpoints {
|
||||||
public static readonly Development: string = "https://localhost:7238";
|
public static readonly Local: string = "https://localhost:7238";
|
||||||
public static readonly Mpac: string = "https://cdb-ms-mpac-mp.cosmos.azure.com";
|
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 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 Fairfax: string = "https://cdb-ff-prod-mp.cosmos.azure.us";
|
||||||
|
|
|
@ -672,6 +672,27 @@ export function getEndpoint(endpoint: string): string {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useMongoProxyEndpoint(api: string): boolean {
|
||||||
|
const activeMongoProxyEndpoints: string[] = [
|
||||||
|
MongoProxyEndpoints.Local,
|
||||||
|
MongoProxyEndpoints.Mpac,
|
||||||
|
MongoProxyEndpoints.Prod,
|
||||||
|
];
|
||||||
|
let canAccessMongoProxy: boolean = userContext.databaseAccount.properties.publicNetworkAccess === "Enabled";
|
||||||
|
if (
|
||||||
|
configContext.MONGO_PROXY_ENDPOINT !== MongoProxyEndpoints.Local &&
|
||||||
|
userContext.databaseAccount.properties.ipRules?.length > 0
|
||||||
|
) {
|
||||||
|
canAccessMongoProxy = canAccessMongoProxy && configContext.MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
canAccessMongoProxy &&
|
||||||
|
configContext.NEW_MONGO_APIS?.includes(api) &&
|
||||||
|
activeMongoProxyEndpoints.includes(configContext.MONGO_PROXY_ENDPOINT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This function throws most of the time except on Forbidden which is a bit strange
|
// TODO: This function throws most of the time except on Forbidden which is a bit strange
|
||||||
// It causes problems for TypeScript understanding the types
|
// It causes problems for TypeScript understanding the types
|
||||||
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
||||||
|
@ -688,24 +709,3 @@ async function errorHandling(response: Response, action: string, params: unknown
|
||||||
export function getARMCreateCollectionEndpoint(params: DataModels.MongoParameters): string {
|
export function getARMCreateCollectionEndpoint(params: DataModels.MongoParameters): string {
|
||||||
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/mongodbDatabases/${params.db}/collections/${params.coll}`;
|
return `subscriptions/${params.sid}/resourceGroups/${params.rg}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/mongodbDatabases/${params.db}/collections/${params.coll}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useMongoProxyEndpoint(api: string): boolean {
|
|
||||||
const activeMongoProxyEndpoints: string[] = [
|
|
||||||
MongoProxyEndpoints.Development,
|
|
||||||
MongoProxyEndpoints.Mpac,
|
|
||||||
MongoProxyEndpoints.Prod,
|
|
||||||
];
|
|
||||||
let canAccessMongoProxy: boolean = userContext.databaseAccount.properties.publicNetworkAccess === "Enabled";
|
|
||||||
if (
|
|
||||||
configContext.MONGO_PROXY_ENDPOINT !== MongoProxyEndpoints.Development &&
|
|
||||||
userContext.databaseAccount.properties.ipRules?.length > 0
|
|
||||||
) {
|
|
||||||
canAccessMongoProxy = canAccessMongoProxy && configContext.MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
canAccessMongoProxy &&
|
|
||||||
configContext.NEW_MONGO_APIS?.includes(api) &&
|
|
||||||
activeMongoProxyEndpoints.includes(configContext.MONGO_PROXY_ENDPOINT)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ let configContext: Readonly<ConfigContext> = {
|
||||||
`^https:\\/\\/.*\\.analysis-df\\.net$`,
|
`^https:\\/\\/.*\\.analysis-df\\.net$`,
|
||||||
`^https:\\/\\/.*\\.analysis-df\\.windows\\.net$`,
|
`^https:\\/\\/.*\\.analysis-df\\.windows\\.net$`,
|
||||||
`^https:\\/\\/.*\\.azure-test\\.net$`,
|
`^https:\\/\\/.*\\.azure-test\\.net$`,
|
||||||
|
`^https:\\/\\/cosmos-explorer-preview\\.azurewebsites\\.net`,
|
||||||
], // Webpack injects this at build time
|
], // Webpack injects this at build time
|
||||||
gitSha: process.env.GIT_SHA,
|
gitSha: process.env.GIT_SHA,
|
||||||
hostedExplorerURL: "https://cosmos.azure.com/",
|
hostedExplorerURL: "https://cosmos.azure.com/",
|
||||||
|
@ -108,6 +109,7 @@ let configContext: Readonly<ConfigContext> = {
|
||||||
"updateDocument",
|
"updateDocument",
|
||||||
"deleteDocument",
|
"deleteDocument",
|
||||||
"createCollectionWithProxy",
|
"createCollectionWithProxy",
|
||||||
|
"legacyMongoShell",
|
||||||
],
|
],
|
||||||
MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED: false,
|
MONGO_PROXY_OUTBOUND_IPS_ALLOWLISTED: false,
|
||||||
CASSANDRA_PROXY_ENDPOINT: CassandraProxyEndpoints.Prod,
|
CASSANDRA_PROXY_ENDPOINT: CassandraProxyEndpoints.Prod,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { isInvalidParentFrameOrigin, isReadyMessage } from "../../../Utils/Messa
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import TabsBase from "../TabsBase";
|
import TabsBase from "../TabsBase";
|
||||||
import { getMongoShellOrigin } from "./getMongoShellOrigin";
|
|
||||||
import { getMongoShellUrl } from "./getMongoShellUrl";
|
import { getMongoShellUrl } from "./getMongoShellUrl";
|
||||||
|
|
||||||
//eslint-disable-next-line
|
//eslint-disable-next-line
|
||||||
|
@ -35,7 +34,7 @@ export interface IMongoShellTabAccessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMongoShellTabComponentStates {
|
export interface IMongoShellTabComponentStates {
|
||||||
url: string;
|
url: URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMongoShellTabComponentProps {
|
export interface IMongoShellTabComponentProps {
|
||||||
|
@ -50,13 +49,16 @@ export default class MongoShellTabComponent extends Component<
|
||||||
IMongoShellTabComponentStates
|
IMongoShellTabComponentStates
|
||||||
> {
|
> {
|
||||||
private _logTraces: Map<string, number>;
|
private _logTraces: Map<string, number>;
|
||||||
|
private _useMongoProxyEndpoint: boolean;
|
||||||
|
|
||||||
constructor(props: IMongoShellTabComponentProps) {
|
constructor(props: IMongoShellTabComponentProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this._logTraces = new Map();
|
this._logTraces = new Map();
|
||||||
|
this._useMongoProxyEndpoint = userContext.features.enableLegacyMongoShell;
|
||||||
|
// this._useMongoProxyEndpoint = useMongoProxyEndpoint("legacyMongoShell");
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
url: getMongoShellUrl(),
|
url: getMongoShellUrl(this._useMongoProxyEndpoint),
|
||||||
};
|
};
|
||||||
|
|
||||||
props.onMongoShellTabAccessor({
|
props.onMongoShellTabAccessor({
|
||||||
|
@ -119,9 +121,10 @@ export default class MongoShellTabComponent extends Component<
|
||||||
) + Constants.MongoDBAccounts.defaultPort.toString();
|
) + 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 = configContext.BACKEND_ENDPOINT;
|
const apiEndpoint = this._useMongoProxyEndpoint
|
||||||
|
? configContext.MONGO_PROXY_ENDPOINT
|
||||||
|
: configContext.BACKEND_ENDPOINT;
|
||||||
const encryptedAuthToken: string = userContext.accessToken;
|
const encryptedAuthToken: string = userContext.accessToken;
|
||||||
const targetOrigin = getMongoShellOrigin();
|
|
||||||
|
|
||||||
shellIframe.contentWindow.postMessage(
|
shellIframe.contentWindow.postMessage(
|
||||||
{
|
{
|
||||||
|
@ -137,7 +140,7 @@ export default class MongoShellTabComponent extends Component<
|
||||||
apiEndpoint: apiEndpoint,
|
apiEndpoint: apiEndpoint,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
targetOrigin,
|
window.origin,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +221,7 @@ export default class MongoShellTabComponent extends Component<
|
||||||
name="explorer"
|
name="explorer"
|
||||||
className="iframe"
|
className="iframe"
|
||||||
style={{ width: "100%", height: "100%", border: 0, padding: 0, margin: 0, overflow: "hidden" }}
|
style={{ width: "100%", height: "100%", border: 0, padding: 0, margin: 0, overflow: "hidden" }}
|
||||||
src={this.state.url}
|
src={this.state.url.toString()}
|
||||||
id={this.props.tabsBaseInstance.tabId}
|
id={this.props.tabsBaseInstance.tabId}
|
||||||
onLoad={(event) => this.setContentFocus(event)}
|
onLoad={(event) => this.setContentFocus(event)}
|
||||||
title="Mongo Shell"
|
title="Mongo Shell"
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
import { extractFeatures } from "Platform/Hosted/extractFeatures";
|
|
||||||
import { configContext } from "../../../ConfigContext";
|
|
||||||
import { updateUserContext } from "../../../UserContext";
|
|
||||||
import { getMongoShellOrigin } from "./getMongoShellOrigin";
|
|
||||||
|
|
||||||
describe("getMongoShellOrigin", () => {
|
|
||||||
(window as { origin: string }).origin = "window_origin";
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1": "false",
|
|
||||||
"feature.enableLegacyMongoShellV2": "false",
|
|
||||||
"feature.enableLegacyMongoShellV1Debug": "false",
|
|
||||||
"feature.enableLegacyMongoShellV2Debug": "false",
|
|
||||||
"feature.loadLegacyMongoShellFromBE": "false",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return by default", () => {
|
|
||||||
expect(getMongoShellOrigin()).toBe(window.origin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return window.origin when enableLegacyMongoShellV1", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellOrigin()).toBe(window.origin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return window.origin when enableLegacyMongoShellV2===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV2": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellOrigin()).toBe(window.origin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return window.origin when enableLegacyMongoShellV1Debug===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1Debug": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellOrigin()).toBe(window.origin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return window.origin when enableLegacyMongoShellV2Debug===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV2Debug": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellOrigin()).toBe(window.origin);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return BACKEND_ENDPOINT when loadLegacyMongoShellFromBE===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.loadLegacyMongoShellFromBE": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellOrigin()).toBe(configContext.BACKEND_ENDPOINT);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { configContext } from "../../../ConfigContext";
|
|
||||||
import { userContext } from "../../../UserContext";
|
|
||||||
|
|
||||||
export function getMongoShellOrigin(): string {
|
|
||||||
if (userContext.features.loadLegacyMongoShellFromBE === true) {
|
|
||||||
return configContext.BACKEND_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window.origin;
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { extractFeatures } from "Platform/Hosted/extractFeatures";
|
import { Platform, resetConfigContext, updateConfigContext } from "../../../ConfigContext";
|
||||||
import { Platform, configContext, resetConfigContext, updateConfigContext } from "../../../ConfigContext";
|
|
||||||
import { updateUserContext, userContext } from "../../../UserContext";
|
import { updateUserContext, userContext } from "../../../UserContext";
|
||||||
import { getExtensionEndpoint, getMongoShellUrl } from "./getMongoShellUrl";
|
import { getMongoShellUrl } from "./getMongoShellUrl";
|
||||||
|
|
||||||
const mongoBackendEndpoint = "https://localhost:1234";
|
const mongoBackendEndpoint = "https://localhost:1234";
|
||||||
|
const hostedExplorerURL = "https://cosmos.azure.com/";
|
||||||
|
|
||||||
describe("getMongoShellUrl", () => {
|
describe("getMongoShellUrl", () => {
|
||||||
let queryString = "";
|
let queryString = "";
|
||||||
|
@ -13,6 +13,7 @@ describe("getMongoShellUrl", () => {
|
||||||
|
|
||||||
updateConfigContext({
|
updateConfigContext({
|
||||||
BACKEND_ENDPOINT: mongoBackendEndpoint,
|
BACKEND_ENDPOINT: mongoBackendEndpoint,
|
||||||
|
hostedExplorerURL: hostedExplorerURL,
|
||||||
platform: Platform.Hosted,
|
platform: Platform.Hosted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -32,175 +33,18 @@ describe("getMongoShellUrl", () => {
|
||||||
cassandraEndpoint: "fakeCassandraEndpoint",
|
cassandraEndpoint: "fakeCassandraEndpoint",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1": "false",
|
|
||||||
"feature.enableLegacyMongoShellV2": "false",
|
|
||||||
"feature.enableLegacyMongoShellV1Debug": "false",
|
|
||||||
"feature.enableLegacyMongoShellV2Debug": "false",
|
|
||||||
"feature.loadLegacyMongoShellFromBE": "false",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
portalEnv: "prod",
|
portalEnv: "prod",
|
||||||
});
|
});
|
||||||
|
|
||||||
queryString = `resourceId=${userContext.databaseAccount.id}&accountName=${userContext.databaseAccount.name}&mongoEndpoint=${userContext.databaseAccount.properties.documentEndpoint}`;
|
queryString = `resourceId=${userContext.databaseAccount.id}&accountName=${userContext.databaseAccount.name}&mongoEndpoint=${userContext.databaseAccount.properties.documentEndpoint}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return /mongoshell/indexv2.html by default", () => {
|
it("should return /indexv2.html by default", () => {
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/indexv2.html?${queryString}`);
|
expect(getMongoShellUrl().toString()).toContain(`/indexv2.html?${queryString}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return /mongoshell/indexv2.html when portalEnv==localhost", () => {
|
it("should return /index.html when useMongoProxyEndpoint is true", () => {
|
||||||
updateUserContext({
|
const useMongoProxyEndpoint: boolean = true;
|
||||||
portalEnv: "localhost",
|
expect(getMongoShellUrl(useMongoProxyEndpoint).toString()).toContain(`/index.html?${queryString}`);
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/indexv2.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return /mongoshell/index.html when enableLegacyMongoShellV1===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return /mongoshell/index.html when enableLegacyMongoShellV2===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV2": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/indexv2.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return /mongoshell/index.html when enableLegacyMongoShellV1Debug===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV1Debug": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return /mongoshell/index.html when enableLegacyMongoShellV2Debug===true", () => {
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.enableLegacyMongoShellV2Debug": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getMongoShellUrl()).toBe(`/mongoshell/debug/indexv2.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("loadLegacyMongoShellFromBE===true", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
resetConfigContext();
|
|
||||||
updateConfigContext({
|
|
||||||
BACKEND_ENDPOINT: mongoBackendEndpoint,
|
|
||||||
platform: Platform.Hosted,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateUserContext({
|
|
||||||
features: extractFeatures(
|
|
||||||
new URLSearchParams({
|
|
||||||
"feature.loadLegacyMongoShellFromBE": "true",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return /mongoshell/index.html", () => {
|
|
||||||
const endpoint = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
expect(getMongoShellUrl()).toBe(`${endpoint}/content/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("configContext.platform !== Platform.Hosted, should return /mongoshell/indexv2.html", () => {
|
|
||||||
updateConfigContext({
|
|
||||||
platform: Platform.Portal,
|
|
||||||
});
|
|
||||||
|
|
||||||
const endpoint = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
expect(getMongoShellUrl()).toBe(`${endpoint}/content/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("configContext.BACKEND_ENDPOINT !== '' and configContext.platform !== Platform.Hosted, should return /mongoshell/indexv2.html", () => {
|
|
||||||
resetConfigContext();
|
|
||||||
updateConfigContext({
|
|
||||||
platform: Platform.Portal,
|
|
||||||
BACKEND_ENDPOINT: mongoBackendEndpoint,
|
|
||||||
});
|
|
||||||
|
|
||||||
const endpoint = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
expect(getMongoShellUrl()).toBe(`${endpoint}/content/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("configContext.BACKEND_ENDPOINT === '' and configContext.platform === Platform.Hosted, should return /mongoshell/indexv2.html", () => {
|
|
||||||
resetConfigContext();
|
|
||||||
updateConfigContext({
|
|
||||||
platform: Platform.Hosted,
|
|
||||||
});
|
|
||||||
|
|
||||||
const endpoint = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
expect(getMongoShellUrl()).toBe(`${endpoint}/content/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("configContext.BACKEND_ENDPOINT === '' and configContext.platform !== Platform.Hosted, should return /mongoshell/indexv2.html", () => {
|
|
||||||
resetConfigContext();
|
|
||||||
updateConfigContext({
|
|
||||||
platform: Platform.Portal,
|
|
||||||
});
|
|
||||||
|
|
||||||
const endpoint = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
expect(getMongoShellUrl()).toBe(`${endpoint}/content/mongoshell/debug/index.html?${queryString}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getExtensionEndpoint", () => {
|
|
||||||
it("when platform === Platform.Hosted, backendEndpoint is undefined", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Hosted, undefined)).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Hosted, backendEndpoint === ''", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Hosted, "")).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Hosted, backendEndpoint === null", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Hosted, null)).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Hosted, backendEndpoint != ''", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Hosted, "foo")).toBe("foo");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Portal, backendEndpoint is udefined", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Portal, undefined)).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Portal, backendEndpoint === ''", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Portal, "")).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform === Platform.Portal, backendEndpoint === null", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Portal, null)).toBe("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("when platform !== Platform.Portal, backendEndpoint != ''", () => {
|
|
||||||
expect(getExtensionEndpoint(Platform.Portal, "foo")).toBe("foo");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,45 +1,13 @@
|
||||||
import { configContext, Platform } from "../../../ConfigContext";
|
import { configContext } from "ConfigContext";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
|
|
||||||
export function getMongoShellUrl(): string {
|
export function getMongoShellUrl(useMongoProxyEndpoint?: boolean): URL {
|
||||||
const { databaseAccount: account } = userContext;
|
const { databaseAccount: account } = userContext;
|
||||||
const resourceId = account?.id;
|
const resourceId = account?.id;
|
||||||
const accountName = account?.name;
|
const accountName = account?.name;
|
||||||
const mongoEndpoint = account?.properties?.mongoEndpoint || account?.properties?.documentEndpoint;
|
const mongoEndpoint = account?.properties?.mongoEndpoint || account?.properties?.documentEndpoint;
|
||||||
const queryString = `resourceId=${resourceId}&accountName=${accountName}&mongoEndpoint=${mongoEndpoint}`;
|
const queryString = `resourceId=${resourceId}&accountName=${accountName}&mongoEndpoint=${mongoEndpoint}`;
|
||||||
|
const path: string = useMongoProxyEndpoint ? `/index.html?${queryString}` : `/indexv2.html?${queryString}`;
|
||||||
|
|
||||||
if (userContext.features.enableLegacyMongoShellV1 === true) {
|
return new URL(path, configContext.hostedExplorerURL);
|
||||||
return `/mongoshell/index.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userContext.features.enableLegacyMongoShellV1Debug === true) {
|
|
||||||
return `/mongoshell/debug/index.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userContext.features.enableLegacyMongoShellV2 === true) {
|
|
||||||
return `/mongoshell/indexv2.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userContext.features.enableLegacyMongoShellV2Debug === true) {
|
|
||||||
return `/mongoshell/debug/indexv2.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userContext.portalEnv === "localhost") {
|
|
||||||
return `/mongoshell/indexv2.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userContext.features.loadLegacyMongoShellFromBE === true) {
|
|
||||||
const extensionEndpoint: string = getExtensionEndpoint(configContext.platform, configContext.BACKEND_ENDPOINT);
|
|
||||||
return `${extensionEndpoint}/content/mongoshell/debug/index.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `/mongoshell/indexv2.html?${queryString}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getExtensionEndpoint(platform: string, backendEndpoint: string): string {
|
|
||||||
const runtimeEndpoint = platform === Platform.Hosted ? backendEndpoint : "";
|
|
||||||
|
|
||||||
const extensionEndpoint: string = backendEndpoint || runtimeEndpoint || "";
|
|
||||||
|
|
||||||
return extensionEndpoint;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,7 @@ const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): J
|
||||||
const showMongoAndCassandraProxiesNetworkSettingsWarning = (): boolean => {
|
const showMongoAndCassandraProxiesNetworkSettingsWarning = (): boolean => {
|
||||||
const ipRules: IpRule[] = userContext.databaseAccount?.properties?.ipRules;
|
const ipRules: IpRule[] = userContext.databaseAccount?.properties?.ipRules;
|
||||||
if (
|
if (
|
||||||
((userContext.apiType === "Mongo" && configContext.MONGO_PROXY_ENDPOINT !== MongoProxyEndpoints.Development) ||
|
((userContext.apiType === "Mongo" && configContext.MONGO_PROXY_ENDPOINT !== MongoProxyEndpoints.Local) ||
|
||||||
(userContext.apiType === "Cassandra" &&
|
(userContext.apiType === "Cassandra" &&
|
||||||
configContext.CASSANDRA_PROXY_ENDPOINT !== CassandraProxyEndpoints.Development)) &&
|
configContext.CASSANDRA_PROXY_ENDPOINT !== CassandraProxyEndpoints.Development)) &&
|
||||||
ipRules?.length
|
ipRules?.length
|
||||||
|
|
|
@ -31,11 +31,6 @@ export type Features = {
|
||||||
readonly mongoProxyAPIs?: string;
|
readonly mongoProxyAPIs?: string;
|
||||||
readonly enableThroughputCap: boolean;
|
readonly enableThroughputCap: boolean;
|
||||||
readonly enableHierarchicalKeys: boolean;
|
readonly enableHierarchicalKeys: boolean;
|
||||||
readonly enableLegacyMongoShellV1: boolean;
|
|
||||||
readonly enableLegacyMongoShellV1Debug: boolean;
|
|
||||||
readonly enableLegacyMongoShellV2: boolean;
|
|
||||||
readonly enableLegacyMongoShellV2Debug: boolean;
|
|
||||||
readonly loadLegacyMongoShellFromBE: boolean;
|
|
||||||
readonly enableCopilot: boolean;
|
readonly enableCopilot: boolean;
|
||||||
readonly copilotVersion?: string;
|
readonly copilotVersion?: string;
|
||||||
readonly disableCopilotPhoenixGateaway: boolean;
|
readonly disableCopilotPhoenixGateaway: boolean;
|
||||||
|
@ -43,6 +38,7 @@ export type Features = {
|
||||||
readonly copilotChatFixedMonacoEditorHeight: boolean;
|
readonly copilotChatFixedMonacoEditorHeight: boolean;
|
||||||
readonly enablePriorityBasedExecution: boolean;
|
readonly enablePriorityBasedExecution: boolean;
|
||||||
readonly disableConnectionStringLogin: boolean;
|
readonly disableConnectionStringLogin: boolean;
|
||||||
|
readonly enableLegacyMongoShell: boolean;
|
||||||
|
|
||||||
// can be set via both flight and feature flag
|
// can be set via both flight and feature flag
|
||||||
autoscaleDefault: boolean;
|
autoscaleDefault: boolean;
|
||||||
|
@ -106,11 +102,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
||||||
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
||||||
enableThroughputCap: "true" === get("enablethroughputcap"),
|
enableThroughputCap: "true" === get("enablethroughputcap"),
|
||||||
enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"),
|
enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"),
|
||||||
enableLegacyMongoShellV1: "true" === get("enablelegacymongoshellv1"),
|
|
||||||
enableLegacyMongoShellV1Debug: "true" === get("enablelegacymongoshellv1debug"),
|
|
||||||
enableLegacyMongoShellV2: "true" === get("enablelegacymongoshellv2"),
|
|
||||||
enableLegacyMongoShellV2Debug: "true" === get("enablelegacymongoshellv2debug"),
|
|
||||||
loadLegacyMongoShellFromBE: "true" === get("loadlegacymongoshellfrombe"),
|
|
||||||
enableCopilot: "true" === get("enablecopilot", "true"),
|
enableCopilot: "true" === get("enablecopilot", "true"),
|
||||||
copilotVersion: get("copilotversion") ?? "v2.0",
|
copilotVersion: get("copilotversion") ?? "v2.0",
|
||||||
disableCopilotPhoenixGateaway: "true" === get("disablecopilotphoenixgateaway"),
|
disableCopilotPhoenixGateaway: "true" === get("disablecopilotphoenixgateaway"),
|
||||||
|
@ -118,6 +109,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
||||||
copilotChatFixedMonacoEditorHeight: "true" === get("copilotchatfixedmonacoeditorheight"),
|
copilotChatFixedMonacoEditorHeight: "true" === get("copilotchatfixedmonacoeditorheight"),
|
||||||
enablePriorityBasedExecution: "true" === get("enableprioritybasedexecution"),
|
enablePriorityBasedExecution: "true" === get("enableprioritybasedexecution"),
|
||||||
disableConnectionStringLogin: "true" === get("disableconnectionstringlogin"),
|
disableConnectionStringLogin: "true" === get("disableconnectionstringlogin"),
|
||||||
|
enableLegacyMongoShell: "true" === get("enablelegacymongoshell"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ export const MongoProxyOutboundIPs: { [key: string]: string[] } = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
||||||
MongoProxyEndpoints.Development,
|
MongoProxyEndpoints.Local,
|
||||||
MongoProxyEndpoints.Mpac,
|
MongoProxyEndpoints.Mpac,
|
||||||
MongoProxyEndpoints.Prod,
|
MongoProxyEndpoints.Prod,
|
||||||
MongoProxyEndpoints.Fairfax,
|
MongoProxyEndpoints.Fairfax,
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<clear />
|
<clear />
|
||||||
<add name="X-Xss-Protection" value="1; mode=block" />
|
<add name="X-Xss-Protection" value="1; mode=block" />
|
||||||
<add name="X-Content-Type-Options" value="nosniff" />
|
<add name="X-Content-Type-Options" value="nosniff" />
|
||||||
<add name="Content-Security-Policy" value="frame-ancestors 'self' portal.azure.com *.portal.azure.com portal.azure.us portal.azure.cn portal.microsoftazure.de df.onecloud.azure-test.net *.fabric.microsoft.com *.powerbi.com *.analysis-df.windows.net" />
|
<add name="Content-Security-Policy" value="frame-ancestors 'self' portal.azure.com *.portal.azure.com portal.azure.us portal.azure.cn portal.microsoftazure.de df.onecloud.azure-test.net *.fabric.microsoft.com *.powerbi.com *.analysis-df.windows.net cosmos-explorer-preview.azurewebsites.net" />
|
||||||
</customHeaders>
|
</customHeaders>
|
||||||
<redirectHeaders>
|
<redirectHeaders>
|
||||||
<clear />
|
<clear />
|
||||||
|
|
Loading…
Reference in New Issue