mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-28 13:21:42 +00:00
Compare commits
8 Commits
solution22
...
defect2392
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af0546361 | ||
|
|
e442e5fd0b | ||
|
|
10586d44f8 | ||
|
|
755b732532 | ||
|
|
1b5a9b83ff | ||
|
|
fb8871cfbf | ||
|
|
874cec26fc | ||
|
|
9d2d0e4754 |
@@ -18,7 +18,8 @@ module.exports = {
|
|||||||
// clearMocks: false,
|
// clearMocks: false,
|
||||||
|
|
||||||
// Indicates whether the coverage information should be collected while executing the test
|
// Indicates whether the coverage information should be collected while executing the test
|
||||||
collectCoverage: true,
|
|
||||||
|
collectCoverage: process.env.skipCodeCoverage === "true" ? false : true,
|
||||||
|
|
||||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||||
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
|
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ import {
|
|||||||
import {
|
import {
|
||||||
ChangeFeedPolicyState,
|
ChangeFeedPolicyState,
|
||||||
GeospatialConfigType,
|
GeospatialConfigType,
|
||||||
getSanitizedInputValue,
|
|
||||||
IsComponentDirtyResult,
|
IsComponentDirtyResult,
|
||||||
isDirty,
|
|
||||||
TtlOff,
|
TtlOff,
|
||||||
TtlOn,
|
TtlOn,
|
||||||
TtlOnNoDefault,
|
TtlOnNoDefault,
|
||||||
TtlType,
|
TtlType,
|
||||||
|
getSanitizedInputValue,
|
||||||
|
isDirty,
|
||||||
} from "../SettingsUtils";
|
} from "../SettingsUtils";
|
||||||
import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
|
import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
|
||||||
|
|
||||||
@@ -55,6 +55,18 @@ export interface SubSettingsComponentProps {
|
|||||||
onSubSettingsSaveableChange: (isSubSettingsSaveable: boolean) => void;
|
onSubSettingsSaveableChange: (isSubSettingsSaveable: boolean) => void;
|
||||||
onSubSettingsDiscardableChange: (isSubSettingsDiscardable: boolean) => void;
|
onSubSettingsDiscardableChange: (isSubSettingsDiscardable: boolean) => void;
|
||||||
}
|
}
|
||||||
|
const stylingforvisuallyhiddenspan = {
|
||||||
|
position: "absolute",
|
||||||
|
|
||||||
|
width: "1px",
|
||||||
|
height: "1px",
|
||||||
|
margin: "-1px",
|
||||||
|
border: 0,
|
||||||
|
padding: 0,
|
||||||
|
|
||||||
|
clip: "rect(0 0 0 0)",
|
||||||
|
overflow: "hidden",
|
||||||
|
};
|
||||||
|
|
||||||
export class SubSettingsComponent extends React.Component<SubSettingsComponentProps> {
|
export class SubSettingsComponent extends React.Component<SubSettingsComponentProps> {
|
||||||
private shouldCheckComponentIsDirty = true;
|
private shouldCheckComponentIsDirty = true;
|
||||||
@@ -197,6 +209,10 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
</MessageBar>
|
</MessageBar>
|
||||||
)}
|
)}
|
||||||
{this.props.timeToLive === TtlType.On && (
|
{this.props.timeToLive === TtlType.On && (
|
||||||
|
<div>
|
||||||
|
<span id="timetoliveon" style={stylingforvisuallyhiddenspan}>
|
||||||
|
Time to live on
|
||||||
|
</span>
|
||||||
<TextField
|
<TextField
|
||||||
id="timeToLiveSeconds"
|
id="timeToLiveSeconds"
|
||||||
styles={getTextFieldStyles(this.props.timeToLiveSeconds, this.props.timeToLiveSecondsBaseline)}
|
styles={getTextFieldStyles(this.props.timeToLiveSeconds, this.props.timeToLiveSecondsBaseline)}
|
||||||
@@ -207,7 +223,12 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
value={this.props.timeToLiveSeconds?.toString()}
|
value={this.props.timeToLiveSeconds?.toString()}
|
||||||
onChange={this.onTimeToLiveSecondsChange}
|
onChange={this.onTimeToLiveSecondsChange}
|
||||||
suffix="second(s)"
|
suffix="second(s)"
|
||||||
|
aria-labelledby="timetoliveon secondssuffixforscreenreader"
|
||||||
/>
|
/>
|
||||||
|
<span id="secondssuffixforscreenreader" style={stylingforvisuallyhiddenspan}>
|
||||||
|
Second(s)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -59,7 +59,26 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
id="timetoliveon"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Time to live on
|
||||||
|
</span>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
|
aria-labelledby="timetoliveon secondssuffixforscreenreader"
|
||||||
id="timeToLiveSeconds"
|
id="timeToLiveSeconds"
|
||||||
max={2147483647}
|
max={2147483647}
|
||||||
min={1}
|
min={1}
|
||||||
@@ -84,6 +103,24 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="1000"
|
value="1000"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
id="secondssuffixforscreenreader"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Second(s)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<StyledChoiceGroup
|
<StyledChoiceGroup
|
||||||
id="geoSpatialConfig"
|
id="geoSpatialConfig"
|
||||||
@@ -283,7 +320,26 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
id="timetoliveon"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Time to live on
|
||||||
|
</span>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
|
aria-labelledby="timetoliveon secondssuffixforscreenreader"
|
||||||
id="timeToLiveSeconds"
|
id="timeToLiveSeconds"
|
||||||
max={2147483647}
|
max={2147483647}
|
||||||
min={1}
|
min={1}
|
||||||
@@ -308,6 +364,24 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="1000"
|
value="1000"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
id="secondssuffixforscreenreader"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Second(s)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<StyledChoiceGroup
|
<StyledChoiceGroup
|
||||||
id="geoSpatialConfig"
|
id="geoSpatialConfig"
|
||||||
@@ -560,7 +634,26 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
id="timetoliveon"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Time to live on
|
||||||
|
</span>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
|
aria-labelledby="timetoliveon secondssuffixforscreenreader"
|
||||||
id="timeToLiveSeconds"
|
id="timeToLiveSeconds"
|
||||||
max={2147483647}
|
max={2147483647}
|
||||||
min={1}
|
min={1}
|
||||||
@@ -585,6 +678,24 @@ exports[`SubSettingsComponent changeFeedPolicy hidden 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="1000"
|
value="1000"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
id="secondssuffixforscreenreader"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Second(s)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<StyledChoiceGroup
|
<StyledChoiceGroup
|
||||||
id="geoSpatialConfig"
|
id="geoSpatialConfig"
|
||||||
@@ -799,7 +910,26 @@ exports[`SubSettingsComponent renders 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
id="timetoliveon"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Time to live on
|
||||||
|
</span>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
|
aria-labelledby="timetoliveon secondssuffixforscreenreader"
|
||||||
id="timeToLiveSeconds"
|
id="timeToLiveSeconds"
|
||||||
max={2147483647}
|
max={2147483647}
|
||||||
min={1}
|
min={1}
|
||||||
@@ -824,6 +954,24 @@ exports[`SubSettingsComponent renders 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="1000"
|
value="1000"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
id="secondssuffixforscreenreader"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"border": 0,
|
||||||
|
"clip": "rect(0 0 0 0)",
|
||||||
|
"height": "1px",
|
||||||
|
"margin": "-1px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"padding": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"width": "1px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Second(s)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<StyledChoiceGroup
|
<StyledChoiceGroup
|
||||||
id="geoSpatialConfig"
|
id="geoSpatialConfig"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
updateUserContext({
|
updateUserContext({
|
||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
properties: {
|
properties: {
|
||||||
capabilities: [{ name: "EnableTable" }],
|
capabilities: [{ name: "EnableMongo" }],
|
||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
@@ -38,6 +38,38 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
);
|
);
|
||||||
expect(enableAzureSynapseLinkBtn).toBeDefined();
|
expect(enableAzureSynapseLinkBtn).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Button should not be visible for Tables API", () => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [{ name: "EnableTable" }],
|
||||||
|
},
|
||||||
|
} as DatabaseAccount,
|
||||||
|
});
|
||||||
|
|
||||||
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
|
const enableAzureSynapseLinkBtn = buttons.find(
|
||||||
|
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
||||||
|
);
|
||||||
|
expect(enableAzureSynapseLinkBtn).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Button should not be visible for Cassandra API", () => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [{ name: "EnableCassandra" }],
|
||||||
|
},
|
||||||
|
} as DatabaseAccount,
|
||||||
|
});
|
||||||
|
|
||||||
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
|
const enableAzureSynapseLinkBtn = buttons.find(
|
||||||
|
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
||||||
|
);
|
||||||
|
expect(enableAzureSynapseLinkBtn).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Enable notebook button", () => {
|
describe("Enable notebook button", () => {
|
||||||
|
|||||||
@@ -51,12 +51,14 @@ export function createStaticCommandBarButtons(
|
|||||||
const buttons: CommandButtonComponentProps[] = [];
|
const buttons: CommandButtonComponentProps[] = [];
|
||||||
|
|
||||||
buttons.push(newCollectionBtn);
|
buttons.push(newCollectionBtn);
|
||||||
|
if (userContext.apiType !== "Tables" && userContext.apiType !== "Cassandra") {
|
||||||
const addSynapseLink = createOpenSynapseLinkDialogButton(container);
|
const addSynapseLink = createOpenSynapseLinkDialogButton(container);
|
||||||
|
|
||||||
if (addSynapseLink) {
|
if (addSynapseLink) {
|
||||||
buttons.push(createDivider());
|
buttons.push(createDivider());
|
||||||
buttons.push(addSynapseLink);
|
buttons.push(addSynapseLink);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (userContext.apiType !== "Tables") {
|
if (userContext.apiType !== "Tables") {
|
||||||
newCollectionBtn.children = [createNewCollectionGroup(container)];
|
newCollectionBtn.children = [createNewCollectionGroup(container)];
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { DefaultButton, IconButton, Image, Modal, PrimaryButton, Stack, Text } from "@fluentui/react";
|
import { DefaultButton, IconButton, Image, Modal, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||||
import { useCarousel } from "hooks/useCarousel";
|
|
||||||
import React, { useState } from "react";
|
|
||||||
import Youtube from "react-youtube";
|
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
import { traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
|
import { traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "UserContext";
|
import { userContext } from "UserContext";
|
||||||
|
import { useCarousel } from "hooks/useCarousel";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import Youtube from "react-youtube";
|
||||||
import Image1 from "../../../images/CarouselImage1.svg";
|
import Image1 from "../../../images/CarouselImage1.svg";
|
||||||
import Image2 from "../../../images/CarouselImage2.svg";
|
import Image2 from "../../../images/CarouselImage2.svg";
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export const QuickstartCarousel: React.FC<QuickstartCarouselProps> = ({
|
|||||||
<Stack>
|
<Stack>
|
||||||
<Stack horizontal horizontalAlign="space-between" style={{ padding: 16 }}>
|
<Stack horizontal horizontalAlign="space-between" style={{ padding: 16 }}>
|
||||||
<Text variant="xLarge">{getHeaderText(page)}</Text>
|
<Text variant="xLarge">{getHeaderText(page)}</Text>
|
||||||
<IconButton iconProps={{ iconName: "Cancel" }} onClick={() => setPage(4)} />
|
<IconButton iconProps={{ iconName: "Cancel" }} onClick={() => setPage(4)} ariaLabel="Close"/>
|
||||||
</Stack>
|
</Stack>
|
||||||
{getContent(page)}
|
{getContent(page)}
|
||||||
<Text variant="medium" style={{ padding: "0 16px" }}>
|
<Text variant="medium" style={{ padding: "0 16px" }}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { configContext, Platform } 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";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
@@ -9,6 +9,8 @@ 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";
|
||||||
|
|
||||||
//eslint-disable-next-line
|
//eslint-disable-next-line
|
||||||
class MessageType {
|
class MessageType {
|
||||||
@@ -47,7 +49,6 @@ export default class MongoShellTabComponent extends Component<
|
|||||||
IMongoShellTabComponentProps,
|
IMongoShellTabComponentProps,
|
||||||
IMongoShellTabComponentStates
|
IMongoShellTabComponentStates
|
||||||
> {
|
> {
|
||||||
private _runtimeEndpoint: string;
|
|
||||||
private _logTraces: Map<string, number>;
|
private _logTraces: Map<string, number>;
|
||||||
|
|
||||||
constructor(props: IMongoShellTabComponentProps) {
|
constructor(props: IMongoShellTabComponentProps) {
|
||||||
@@ -55,7 +56,7 @@ export default class MongoShellTabComponent extends Component<
|
|||||||
this._logTraces = new Map();
|
this._logTraces = new Map();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
url: this.getURL(),
|
url: getMongoShellUrl(),
|
||||||
};
|
};
|
||||||
|
|
||||||
props.onMongoShellTabAccessor({
|
props.onMongoShellTabAccessor({
|
||||||
@@ -65,22 +66,6 @@ export default class MongoShellTabComponent extends Component<
|
|||||||
window.addEventListener("message", this.handleMessage.bind(this), false);
|
window.addEventListener("message", this.handleMessage.bind(this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getURL(): string {
|
|
||||||
const { databaseAccount: account } = userContext;
|
|
||||||
const resourceId = account?.id;
|
|
||||||
const accountName = account?.name;
|
|
||||||
const mongoEndpoint = account?.properties?.mongoEndpoint || account?.properties?.documentEndpoint;
|
|
||||||
|
|
||||||
this._runtimeEndpoint = configContext.platform === Platform.Hosted ? configContext.BACKEND_ENDPOINT : "";
|
|
||||||
const extensionEndpoint: string = configContext.BACKEND_ENDPOINT || this._runtimeEndpoint || "";
|
|
||||||
let baseUrl = "/content/mongoshell/dist/";
|
|
||||||
if (userContext.portalEnv === "localhost") {
|
|
||||||
baseUrl = "/content/mongoshell/";
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${extensionEndpoint}${baseUrl}index.html?resourceId=${resourceId}&accountName=${accountName}&mongoEndpoint=${mongoEndpoint}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
//eslint-disable-next-line
|
//eslint-disable-next-line
|
||||||
public setContentFocus(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {}
|
public setContentFocus(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {}
|
||||||
|
|
||||||
@@ -136,6 +121,7 @@ export default class MongoShellTabComponent extends Component<
|
|||||||
const collectionId = this.props.collection.id();
|
const collectionId = this.props.collection.id();
|
||||||
const apiEndpoint = configContext.BACKEND_ENDPOINT;
|
const apiEndpoint = configContext.BACKEND_ENDPOINT;
|
||||||
const encryptedAuthToken: string = userContext.accessToken;
|
const encryptedAuthToken: string = userContext.accessToken;
|
||||||
|
const targetOrigin = getMongoShellOrigin();
|
||||||
|
|
||||||
shellIframe.contentWindow.postMessage(
|
shellIframe.contentWindow.postMessage(
|
||||||
{
|
{
|
||||||
@@ -151,7 +137,7 @@ export default class MongoShellTabComponent extends Component<
|
|||||||
apiEndpoint: apiEndpoint,
|
apiEndpoint: apiEndpoint,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
configContext.BACKEND_ENDPOINT
|
targetOrigin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
86
src/Explorer/Tabs/MongoShellTab/getMongoShellOrigin.test.ts
Normal file
86
src/Explorer/Tabs/MongoShellTab/getMongoShellOrigin.test.ts
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
10
src/Explorer/Tabs/MongoShellTab/getMongoShellOrigin.ts
Normal file
10
src/Explorer/Tabs/MongoShellTab/getMongoShellOrigin.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { configContext } from "../../../ConfigContext";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
|
||||||
|
export function getMongoShellOrigin(): string {
|
||||||
|
if (userContext.features.loadLegacyMongoShellFromBE === true) {
|
||||||
|
return configContext.BACKEND_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window.origin;
|
||||||
|
}
|
||||||
206
src/Explorer/Tabs/MongoShellTab/getMongoShellUrl.test.ts
Normal file
206
src/Explorer/Tabs/MongoShellTab/getMongoShellUrl.test.ts
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
import { extractFeatures } from "Platform/Hosted/extractFeatures";
|
||||||
|
import { Platform, configContext, resetConfigContext, updateConfigContext } from "../../../ConfigContext";
|
||||||
|
import { updateUserContext, userContext } from "../../../UserContext";
|
||||||
|
import { getExtensionEndpoint, getMongoShellUrl } from "./getMongoShellUrl";
|
||||||
|
|
||||||
|
const mongoBackendEndpoint = "https://localhost:1234";
|
||||||
|
|
||||||
|
describe("getMongoShellUrl", () => {
|
||||||
|
let queryString = "";
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
resetConfigContext();
|
||||||
|
|
||||||
|
updateConfigContext({
|
||||||
|
BACKEND_ENDPOINT: mongoBackendEndpoint,
|
||||||
|
platform: Platform.Hosted,
|
||||||
|
});
|
||||||
|
|
||||||
|
updateUserContext({
|
||||||
|
subscriptionId: "fakeSubscriptionId",
|
||||||
|
resourceGroup: "fakeResourceGroup",
|
||||||
|
databaseAccount: {
|
||||||
|
id: "fakeId",
|
||||||
|
name: "fakeName",
|
||||||
|
location: "fakeLocation",
|
||||||
|
type: "fakeType",
|
||||||
|
kind: "fakeKind",
|
||||||
|
properties: {
|
||||||
|
documentEndpoint: "fakeDocumentEndpoint",
|
||||||
|
tableEndpoint: "fakeTableEndpoint",
|
||||||
|
gremlinEndpoint: "fakeGremlinEndpoint",
|
||||||
|
cassandraEndpoint: "fakeCassandraEndpoint",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
features: extractFeatures(
|
||||||
|
new URLSearchParams({
|
||||||
|
"feature.enableLegacyMongoShellV1": "false",
|
||||||
|
"feature.enableLegacyMongoShellV2": "false",
|
||||||
|
"feature.enableLegacyMongoShellV1Debug": "false",
|
||||||
|
"feature.enableLegacyMongoShellV2Debug": "false",
|
||||||
|
"feature.loadLegacyMongoShellFromBE": "false",
|
||||||
|
})
|
||||||
|
),
|
||||||
|
portalEnv: "prod",
|
||||||
|
});
|
||||||
|
|
||||||
|
queryString = `resourceId=${userContext.databaseAccount.id}&accountName=${userContext.databaseAccount.name}&mongoEndpoint=${userContext.databaseAccount.properties.documentEndpoint}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return /mongoshell/indexv2.html by default ", () => {
|
||||||
|
expect(getMongoShellUrl()).toBe(`/mongoshell/indexv2.html?${queryString}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return /mongoshell/indexv2.html when portalEnv==localhost ", () => {
|
||||||
|
updateUserContext({
|
||||||
|
portalEnv: "localhost",
|
||||||
|
});
|
||||||
|
|
||||||
|
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");
|
||||||
|
});
|
||||||
|
});
|
||||||
45
src/Explorer/Tabs/MongoShellTab/getMongoShellUrl.ts
Normal file
45
src/Explorer/Tabs/MongoShellTab/getMongoShellUrl.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { configContext, Platform } from "../../../ConfigContext";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
|
||||||
|
export function getMongoShellUrl(): string {
|
||||||
|
const { databaseAccount: account } = userContext;
|
||||||
|
const resourceId = account?.id;
|
||||||
|
const accountName = account?.name;
|
||||||
|
const mongoEndpoint = account?.properties?.mongoEndpoint || account?.properties?.documentEndpoint;
|
||||||
|
const queryString = `resourceId=${resourceId}&accountName=${accountName}&mongoEndpoint=${mongoEndpoint}`;
|
||||||
|
|
||||||
|
if (userContext.features.enableLegacyMongoShellV1 === true) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -134,6 +134,7 @@
|
|||||||
data-bind="click: selectQueryOptions, event: { keydown: onselectQueryOptionsKeyDown }"
|
data-bind="click: selectQueryOptions, event: { keydown: onselectQueryOptionsKeyDown }"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
|
href=""
|
||||||
>
|
>
|
||||||
<span>Choose Columns... </span>
|
<span>Choose Columns... </span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ 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;
|
||||||
|
|
||||||
// can be set via both flight and feature flag
|
// can be set via both flight and feature flag
|
||||||
autoscaleDefault: boolean;
|
autoscaleDefault: boolean;
|
||||||
@@ -92,6 +97,11 @@ 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"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user