mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-23 11:44:03 +00:00
Compare commits
3 Commits
defect2392
...
users/v-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
863fdb4f7e | ||
|
|
c9bd0b6c7f | ||
|
|
8ce7aaa728 |
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -23,6 +23,5 @@
|
|||||||
"source.fixAll.eslint": true,
|
"source.fixAll.eslint": true,
|
||||||
"source.organizeImports": true
|
"source.organizeImports": true
|
||||||
},
|
},
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
"typescript.preferences.importModuleSpecifier": "non-relative"
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,6 @@
|
|||||||
"pack:fast": "webpack --mode development --progress",
|
"pack:fast": "webpack --mode development --progress",
|
||||||
"copyToConsumers": "node copyToConsumers",
|
"copyToConsumers": "node copyToConsumers",
|
||||||
"test": "rimraf coverage && jest",
|
"test": "rimraf coverage && jest",
|
||||||
"test:debug": "jest --runInBand",
|
|
||||||
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
|
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
|
||||||
"watch": "npm run start",
|
"watch": "npm run start",
|
||||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ let configContext: Readonly<ConfigContext> = {
|
|||||||
ARM_AUTH_AREA: "https://management.azure.com/",
|
ARM_AUTH_AREA: "https://management.azure.com/",
|
||||||
ARM_ENDPOINT: "https://management.azure.com/",
|
ARM_ENDPOINT: "https://management.azure.com/",
|
||||||
ARM_API_VERSION: "2016-06-01",
|
ARM_API_VERSION: "2016-06-01",
|
||||||
GRAPH_ENDPOINT: "https://graph.microsoft.com",
|
GRAPH_ENDPOINT: "https://graph.windows.net",
|
||||||
GRAPH_API_VERSION: "1.6",
|
GRAPH_API_VERSION: "1.6",
|
||||||
ARCADIA_ENDPOINT: "https://workspaceartifacts.projectarcadia.net",
|
ARCADIA_ENDPOINT: "https://workspaceartifacts.projectarcadia.net",
|
||||||
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
|
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
|
||||||
|
|||||||
@@ -32,20 +32,6 @@ const testCassandraAccount: DataModels.DatabaseAccount = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const testPostgresAccount: DataModels.DatabaseAccount = {
|
|
||||||
...testAccount,
|
|
||||||
properties: {
|
|
||||||
postgresqlEndpoint: "https://testPostgresEndpoint.azure.com/",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const testVCoreMongoAccount: DataModels.DatabaseAccount = {
|
|
||||||
...testAccount,
|
|
||||||
properties: {
|
|
||||||
vcoreMongoEndpoint: "https://testVCoreMongoEndpoint.azure.com/",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const testNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
const testNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
||||||
authToken: "authToken",
|
authToken: "authToken",
|
||||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com",
|
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com",
|
||||||
@@ -64,18 +50,6 @@ const testCassandraNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInf
|
|||||||
forwardingId: "Id",
|
forwardingId: "Id",
|
||||||
};
|
};
|
||||||
|
|
||||||
const testPostgresNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
|
||||||
authToken: "authToken",
|
|
||||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/postgresql",
|
|
||||||
forwardingId: "Id",
|
|
||||||
};
|
|
||||||
|
|
||||||
const testVCoreMongoNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
|
|
||||||
authToken: "authToken",
|
|
||||||
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/mongovcore",
|
|
||||||
forwardingId: "Id",
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("NotebookTerminalComponent", () => {
|
describe("NotebookTerminalComponent", () => {
|
||||||
it("renders terminal", () => {
|
it("renders terminal", () => {
|
||||||
const props: NotebookTerminalComponentProps = {
|
const props: NotebookTerminalComponentProps = {
|
||||||
@@ -120,27 +94,4 @@ describe("NotebookTerminalComponent", () => {
|
|||||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders Postgres shell", () => {
|
|
||||||
const props: NotebookTerminalComponentProps = {
|
|
||||||
databaseAccount: testPostgresAccount,
|
|
||||||
notebookServerInfo: testPostgresNotebookServerInfo,
|
|
||||||
tabId: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renders vCore Mongo shell", () => {
|
|
||||||
const props: NotebookTerminalComponentProps = {
|
|
||||||
databaseAccount: testVCoreMongoAccount,
|
|
||||||
notebookServerInfo: testVCoreMongoNotebookServerInfo,
|
|
||||||
tabId: undefined,
|
|
||||||
username: "username",
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,5 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`NotebookTerminalComponent renders Postgres shell 1`] = `
|
|
||||||
<div
|
|
||||||
className="notebookTerminalContainer"
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="terminal.html"
|
|
||||||
title="Terminal to Notebook Server"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`NotebookTerminalComponent renders cassandra shell 1`] = `
|
exports[`NotebookTerminalComponent renders cassandra shell 1`] = `
|
||||||
<div
|
<div
|
||||||
className="notebookTerminalContainer"
|
className="notebookTerminalContainer"
|
||||||
@@ -59,15 +47,3 @@ exports[`NotebookTerminalComponent renders terminal 1`] = `
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`NotebookTerminalComponent renders vCore Mongo shell 1`] = `
|
|
||||||
<div
|
|
||||||
className="notebookTerminalContainer"
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
onLoad={[Function]}
|
|
||||||
src="terminal.html"
|
|
||||||
title="Terminal to Notebook Server"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -343,31 +343,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Open Postgres and vCore Mongo buttons", () => {
|
|
||||||
const openPostgresShellButtonLabel = "Open PSQL shell";
|
|
||||||
const openVCoreMongoShellButtonLabel = "Open MongoDB (vcore) shell";
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
mockExplorer = {} as Explorer;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("creates Postgres shell button", () => {
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createPostgreButtons(mockExplorer);
|
|
||||||
const openPostgresShellButton = buttons.find(
|
|
||||||
(button) => button.commandButtonLabel === openPostgresShellButtonLabel
|
|
||||||
);
|
|
||||||
expect(openPostgresShellButton).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("creates vCore Mongo shell button", () => {
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createVCoreMongoButtons(mockExplorer);
|
|
||||||
const openVCoreMongoShellButton = buttons.find(
|
|
||||||
(button) => button.commandButtonLabel === openVCoreMongoShellButtonLabel
|
|
||||||
);
|
|
||||||
expect(openVCoreMongoShellButton).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("GitHub buttons", () => {
|
describe("GitHub buttons", () => {
|
||||||
const connectToGitHubBtnLabel = "Connect to GitHub";
|
const connectToGitHubBtnLabel = "Connect to GitHub";
|
||||||
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
import {
|
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
|
||||||
DetailsList,
|
|
||||||
DetailsListLayoutMode,
|
|
||||||
DirectionalHint,
|
|
||||||
IColumn,
|
|
||||||
SelectionMode,
|
|
||||||
TooltipHost,
|
|
||||||
} from "@fluentui/react";
|
|
||||||
import { Upload } from "Common/Upload/Upload";
|
import { Upload } from "Common/Upload/Upload";
|
||||||
import { UploadDetailsRecord } from "Contracts/ViewModels";
|
import { UploadDetailsRecord } from "Contracts/ViewModels";
|
||||||
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
|
||||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||||
|
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
||||||
import { getErrorMessage } from "../../Tables/Utilities";
|
import { getErrorMessage } from "../../Tables/Utilities";
|
||||||
import { useSelectedNode } from "../../useSelectedNode";
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
@@ -81,21 +74,12 @@ export const UploadItemsPane: FunctionComponent = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const _renderItemColumn = (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
const _renderItemColumn = (item: UploadDetailsRecord, index: number, column: IColumn) => {
|
||||||
let fieldContent: string;
|
|
||||||
const tooltipId = `tooltip-${index}-${column.key}`;
|
|
||||||
|
|
||||||
switch (column.key) {
|
switch (column.key) {
|
||||||
case "status":
|
case "status":
|
||||||
fieldContent = `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
|
return `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
fieldContent = item.fileName;
|
return item.fileName;
|
||||||
}
|
}
|
||||||
return (
|
|
||||||
<TooltipHost content={fieldContent} id={tooltipId} directionalHint={DirectionalHint.rightCenter}>
|
|
||||||
{fieldContent}
|
|
||||||
</TooltipHost>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
|||||||
<Text>
|
<Text>
|
||||||
Ask Copilot to generate a query by describing the query in your words.
|
Ask Copilot to generate a query by describing the query in your words.
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item align="center" className="text">
|
<Stack.Item align="center" className="text">
|
||||||
@@ -78,7 +78,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
|||||||
<Text>
|
<Text>
|
||||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
<Stack.Item align="center" className="text">
|
<Stack.Item align="center" className="text">
|
||||||
@@ -97,7 +97,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
|
|||||||
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you
|
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you
|
||||||
at no cost.
|
at no cost.
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
|||||||
Ask Copilot to generate a query by describing the query in your words.
|
Ask Copilot to generate a query by describing the query in your words.
|
||||||
<br />
|
<br />
|
||||||
<StyledLinkBase
|
<StyledLinkBase
|
||||||
href="https://aka.ms/cdb-copilot-learn-more"
|
href="http://aka.ms/cdb-copilot-learn-more"
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</StyledLinkBase>
|
</StyledLinkBase>
|
||||||
@@ -138,7 +138,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
|||||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||||
<br />
|
<br />
|
||||||
<StyledLinkBase
|
<StyledLinkBase
|
||||||
href="https://aka.ms/cdb-copilot-preview-terms"
|
href="http://aka.ms/cdb-copilot-preview-terms"
|
||||||
>
|
>
|
||||||
Read preview terms
|
Read preview terms
|
||||||
</StyledLinkBase>
|
</StyledLinkBase>
|
||||||
@@ -174,7 +174,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
|
|||||||
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you at no cost.
|
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you at no cost.
|
||||||
<br />
|
<br />
|
||||||
<StyledLinkBase
|
<StyledLinkBase
|
||||||
href="https://aka.ms/cdb-copilot-learn-more"
|
href="http://aka.ms/cdb-copilot-learn-more"
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more
|
||||||
</StyledLinkBase>
|
</StyledLinkBase>
|
||||||
|
|||||||
@@ -434,7 +434,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Learn about{" "}
|
Learn about{" "}
|
||||||
<Link target="_blank" href="https://aka.ms/cdb-copilot-writing">
|
<Link target="_blank" href="http://aka.ms/cdb-copilot-writing">
|
||||||
writing effective prompts
|
writing effective prompts
|
||||||
</Link>
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
@@ -448,7 +448,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
|
|||||||
<Stack style={{ marginTop: 8, marginBottom: 24 }}>
|
<Stack style={{ marginTop: 8, marginBottom: 24 }}>
|
||||||
<Text style={{ fontSize: 12 }}>
|
<Text style={{ fontSize: 12 }}>
|
||||||
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "}
|
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.{" "}
|
||||||
<Link href="https://aka.ms/cdb-copilot-preview-terms" target="_blank">
|
<Link href="http://aka.ms/cdb-copilot-preview-terms" target="_blank">
|
||||||
Read preview terms
|
Read preview terms
|
||||||
</Link>
|
</Link>
|
||||||
{showErrorMessageBar && (
|
{showErrorMessageBar && (
|
||||||
|
|||||||
@@ -1,39 +1,81 @@
|
|||||||
import { IconButton, Image, Stack, Text } from "@fluentui/react";
|
import { DefaultButton, IconButton, Image, Modal, PrimaryButton, Stack, Text } from "@fluentui/react";
|
||||||
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
import { useQueryCopilot } from "hooks/useQueryCopilot";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import CopilotIcon from "../../../../../images/CopilotSidebarLogo.svg";
|
import CopilotIcon from "../../../../../images/CopilotSidebarLogo.svg";
|
||||||
|
|
||||||
export const Header: React.FC = (): JSX.Element => {
|
export const Header: React.FC = (): JSX.Element => {
|
||||||
const { setShowCopilotSidebar } = useQueryCopilot();
|
const { setShowCopilotSidebar, chatMessages, setChatMessages, setShowExplanationBubble } = useQueryCopilot();
|
||||||
|
const [showDeleteHistoryModal, setShowDeleteHistoryModal] = React.useState(false);
|
||||||
|
|
||||||
|
const getDeleteHistoryModal = () => {
|
||||||
|
return (
|
||||||
|
<Modal isOpen={showDeleteHistoryModal} styles={{ main: { minHeight: "122px", minWidth: "480px" } }}>
|
||||||
|
<Stack style={{ padding: "16px 24px", height: "auto" }}>
|
||||||
|
<Text style={{ height: 24, fontSize: "18px" }}>
|
||||||
|
<b>Delete chat history?</b>
|
||||||
|
</Text>
|
||||||
|
<Text style={{ marginTop: 10, marginBottom: 20 }}>
|
||||||
|
This action will clear all chat history. Are you sure you want to continue?
|
||||||
|
</Text>
|
||||||
|
<Stack horizontal tokens={{ childrenGap: 10 }} horizontalAlign="start">
|
||||||
|
<PrimaryButton
|
||||||
|
style={{ padding: "0px 20px", height: 24 }}
|
||||||
|
onClick={() => {
|
||||||
|
setChatMessages([]);
|
||||||
|
setShowExplanationBubble(false);
|
||||||
|
setShowDeleteHistoryModal(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</PrimaryButton>
|
||||||
|
<DefaultButton style={{ padding: "0px 20px", height: 24 }} onClick={() => setShowDeleteHistoryModal(false)}>
|
||||||
|
Close
|
||||||
|
</DefaultButton>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<>
|
||||||
style={{ margin: "15px 0px 0px 0px", padding: "5px", display: "flex", justifyContent: "space-between" }}
|
<Stack
|
||||||
horizontal
|
style={{ margin: "15px 0px 0px 0px", padding: "5px", display: "flex", justifyContent: "space-between" }}
|
||||||
verticalAlign="center"
|
horizontal
|
||||||
>
|
verticalAlign="center"
|
||||||
<Stack horizontal verticalAlign="center">
|
>
|
||||||
<Image src={CopilotIcon} />
|
<Stack horizontal verticalAlign="center">
|
||||||
<Text style={{ marginLeft: "5px", fontWeight: "bold" }}>Copilot</Text>
|
<Image src={CopilotIcon} />
|
||||||
<Text
|
<Text style={{ marginLeft: "5px", fontWeight: "bold" }}>Copilot</Text>
|
||||||
style={{
|
<Text
|
||||||
background: "#f0f0f0",
|
style={{
|
||||||
fontSize: "10px",
|
background: "#f0f0f0",
|
||||||
padding: "2px 4px",
|
fontSize: "10px",
|
||||||
marginLeft: "5px",
|
padding: "2px 4px",
|
||||||
borderRadius: "8px",
|
marginLeft: "5px",
|
||||||
}}
|
borderRadius: "8px",
|
||||||
>
|
}}
|
||||||
Preview
|
>
|
||||||
</Text>
|
Preview
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setShowDeleteHistoryModal(true)}
|
||||||
|
iconProps={{ iconName: "History" }}
|
||||||
|
title="Delete history"
|
||||||
|
ariaLabel="Delete history"
|
||||||
|
style={{ color: "#424242", verticalAlign: "middle" }}
|
||||||
|
disabled={chatMessages.length === 0}
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => setShowCopilotSidebar(false)}
|
||||||
|
iconProps={{ iconName: "Cancel" }}
|
||||||
|
title="Exit"
|
||||||
|
ariaLabel="Exit"
|
||||||
|
style={{ color: "#424242", verticalAlign: "middle" }}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<IconButton
|
{getDeleteHistoryModal()}
|
||||||
onClick={() => setShowCopilotSidebar(false)}
|
</>
|
||||||
iconProps={{ iconName: "Cancel" }}
|
|
||||||
title="Exit"
|
|
||||||
ariaLabel="Exit"
|
|
||||||
style={{ color: "#424242", verticalAlign: "middle" }}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,64 +1,158 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Header snapshot test should close on button click 1`] = `
|
exports[`Header snapshot test should close on button click 1`] = `
|
||||||
<Stack
|
<Fragment>
|
||||||
horizontal={true}
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"display": "flex",
|
|
||||||
"justifyContent": "space-between",
|
|
||||||
"margin": "15px 0px 0px 0px",
|
|
||||||
"padding": "5px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
verticalAlign="center"
|
|
||||||
>
|
|
||||||
<Stack
|
<Stack
|
||||||
horizontal={true}
|
horizontal={true}
|
||||||
verticalAlign="center"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={Object {}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"fontWeight": "bold",
|
|
||||||
"marginLeft": "5px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Copilot
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={
|
|
||||||
Object {
|
|
||||||
"background": "#f0f0f0",
|
|
||||||
"borderRadius": "8px",
|
|
||||||
"fontSize": "10px",
|
|
||||||
"marginLeft": "5px",
|
|
||||||
"padding": "2px 4px",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Preview
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
<CustomizedIconButton
|
|
||||||
ariaLabel="Exit"
|
|
||||||
iconProps={
|
|
||||||
Object {
|
|
||||||
"iconName": "Cancel",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClick={[Function]}
|
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"color": "#424242",
|
"display": "flex",
|
||||||
"verticalAlign": "middle",
|
"justifyContent": "space-between",
|
||||||
|
"margin": "15px 0px 0px 0px",
|
||||||
|
"padding": "5px",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
title="Exit"
|
verticalAlign="center"
|
||||||
/>
|
>
|
||||||
</Stack>
|
<Stack
|
||||||
|
horizontal={true}
|
||||||
|
verticalAlign="center"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={Object {}}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"fontWeight": "bold",
|
||||||
|
"marginLeft": "5px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Copilot
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"background": "#f0f0f0",
|
||||||
|
"borderRadius": "8px",
|
||||||
|
"fontSize": "10px",
|
||||||
|
"marginLeft": "5px",
|
||||||
|
"padding": "2px 4px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Preview
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
<CustomizedIconButton
|
||||||
|
ariaLabel="Delete history"
|
||||||
|
disabled={true}
|
||||||
|
iconProps={
|
||||||
|
Object {
|
||||||
|
"iconName": "History",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClick={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "#424242",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
title="Delete history"
|
||||||
|
/>
|
||||||
|
<CustomizedIconButton
|
||||||
|
ariaLabel="Exit"
|
||||||
|
iconProps={
|
||||||
|
Object {
|
||||||
|
"iconName": "Cancel",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClick={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "#424242",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
title="Exit"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Modal
|
||||||
|
isOpen={true}
|
||||||
|
styles={
|
||||||
|
Object {
|
||||||
|
"main": Object {
|
||||||
|
"minHeight": "122px",
|
||||||
|
"minWidth": "480px",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": "auto",
|
||||||
|
"padding": "16px 24px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"fontSize": "18px",
|
||||||
|
"height": 24,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<b>
|
||||||
|
Delete chat history?
|
||||||
|
</b>
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginBottom": 20,
|
||||||
|
"marginTop": 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
This action will clear all chat history. Are you sure you want to continue?
|
||||||
|
</Text>
|
||||||
|
<Stack
|
||||||
|
horizontal={true}
|
||||||
|
horizontalAlign="start"
|
||||||
|
tokens={
|
||||||
|
Object {
|
||||||
|
"childrenGap": 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CustomizedPrimaryButton
|
||||||
|
onClick={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": 24,
|
||||||
|
"padding": "0px 20px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</CustomizedPrimaryButton>
|
||||||
|
<CustomizedDefaultButton
|
||||||
|
onClick={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": 24,
|
||||||
|
"padding": "0px 20px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</CustomizedDefaultButton>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
</Fragment>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
|||||||
<Text>
|
<Text>
|
||||||
Ask Copilot to generate a query by describing the query in your words.
|
Ask Copilot to generate a query by describing the query in your words.
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -87,7 +87,7 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
|||||||
<Text>
|
<Text>
|
||||||
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
AI-generated content can have mistakes. Make sure it’s accurate and appropriate before using it.
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -109,7 +109,7 @@ export const WelcomeSidebarModal: React.FC = (): JSX.Element => {
|
|||||||
<Text>
|
<Text>
|
||||||
Copilot is setup on a sample database we have configured for you at no cost
|
Copilot is setup on a sample database we have configured for you at no cost
|
||||||
<br />
|
<br />
|
||||||
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
|
||||||
</Text>
|
</Text>
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ exports[`Query copilot tab snapshot test should render with initial input 1`] =
|
|||||||
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.
|
AI-generated content can have mistakes. Make sure it's accurate and appropriate before using it.
|
||||||
|
|
||||||
<StyledLinkBase
|
<StyledLinkBase
|
||||||
href="https://aka.ms/cdb-copilot-preview-terms"
|
href="http://aka.ms/cdb-copilot-preview-terms"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Read preview terms
|
Read preview terms
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
|
|||||||
import { userContext } from "UserContext";
|
import { userContext } from "UserContext";
|
||||||
import { useCarousel } from "hooks/useCarousel";
|
import { useCarousel } from "hooks/useCarousel";
|
||||||
import React, { useState } from "react";
|
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";
|
||||||
|
|
||||||
@@ -78,12 +79,7 @@ const getHeaderText = (page: number): string => {
|
|||||||
const getContent = (page: number): JSX.Element => {
|
const getContent = (page: number): JSX.Element => {
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case 1:
|
case 1:
|
||||||
return (
|
return <Youtube videoId="Jvgh64rvdXU" onPlay={() => traceSuccess(Action.PlayCarouselVideo)} />;
|
||||||
<video controls width="640" height="360" controlsList="nofullscreen nodownload ">
|
|
||||||
<source src="src/Explorer/Quickstart/Videos/Cosmos-db-turorial.mp4" type="video/mp4"></source>
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
);
|
|
||||||
case 2:
|
case 2:
|
||||||
return <Image style={{ width: 640 }} src={Image1} />;
|
return <Image style={{ width: 640 }} src={Image1} />;
|
||||||
case 3:
|
case 3:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,91 +0,0 @@
|
|||||||
import { DatabaseAccount, FirewallRule } from "Contracts/DataModels";
|
|
||||||
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
|
||||||
import { updateUserContext } from "UserContext";
|
|
||||||
import { mockFunction } from "Utils/JestUtils";
|
|
||||||
import { armRequest } from "Utils/arm/request";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
jest.mock("Utils/arm/request");
|
|
||||||
const armRequestMock = mockFunction(armRequest);
|
|
||||||
|
|
||||||
describe("CheckFirewallRule tests", () => {
|
|
||||||
const apiVersion = "2023-03-15-preview";
|
|
||||||
const rulePredicate = (rule: FirewallRule) =>
|
|
||||||
rule.properties.startIpAddress === "0.0.0.0" && rule.properties.endIpAddress === "255.255.255.255";
|
|
||||||
let isAllPublicIPAddressEnabled: boolean;
|
|
||||||
const setIsAllPublicIPAddressEnabled = jest.fn((value) => (isAllPublicIPAddressEnabled = value));
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const useStateMock: any = (initState: any) => [initState, setIsAllPublicIPAddressEnabled];
|
|
||||||
jest.spyOn(React, "useState").mockImplementation(useStateMock);
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
id: "testResourceId",
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'all public IP addresses' is enabled for account with the proper firewall rule", async () => {
|
|
||||||
armRequestMock.mockResolvedValueOnce({
|
|
||||||
value: [
|
|
||||||
{
|
|
||||||
id: "resourceId",
|
|
||||||
name: "AllowAll",
|
|
||||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
|
||||||
properties: {
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
startIpAddress: "0.0.0.0",
|
|
||||||
endIpAddress: "255.255.255.255",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
await checkFirewallRules(apiVersion, rulePredicate, setIsAllPublicIPAddressEnabled);
|
|
||||||
|
|
||||||
expect(isAllPublicIPAddressEnabled).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 'all public IP addresses' is NOT enabled for account without the proper firewall rule", async () => {
|
|
||||||
armRequestMock.mockResolvedValueOnce([
|
|
||||||
{
|
|
||||||
id: "resourceId",
|
|
||||||
name: "AllowAll",
|
|
||||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
|
||||||
properties: {
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
startIpAddress: "10.10.10.10",
|
|
||||||
endIpAddress: "10.10.10.10",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
await checkFirewallRules(apiVersion, rulePredicate, setIsAllPublicIPAddressEnabled);
|
|
||||||
|
|
||||||
expect(isAllPublicIPAddressEnabled).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets message for account without the proper firewall rule", async () => {
|
|
||||||
armRequestMock.mockResolvedValueOnce([
|
|
||||||
{
|
|
||||||
id: "resourceId",
|
|
||||||
name: "AllowAll",
|
|
||||||
type: "Microsoft.DocumentDB/mongoClusters/firewallRules",
|
|
||||||
properties: {
|
|
||||||
provisioningState: "Succeeded",
|
|
||||||
startIpAddress: "0.0.0.0",
|
|
||||||
endIpAddress: "255.255.255.255",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const warningMessage = "This is a warning message";
|
|
||||||
let warningMessageResult: string;
|
|
||||||
const warningMessageFunc = (msg: string) => (warningMessageResult = msg);
|
|
||||||
|
|
||||||
await checkFirewallRules(apiVersion, rulePredicate, undefined, warningMessageFunc, warningMessage);
|
|
||||||
|
|
||||||
expect(warningMessageResult).toEqual(warningMessage);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -55,17 +55,6 @@ export const defaultAllowedBackendEndpoints: ReadonlyArray<string> = [
|
|||||||
"https://localhost:1234",
|
"https://localhost:1234",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const PortalBackendIPs: { [key: string]: string[] } = {
|
|
||||||
"https://main.documentdb.ext.azure.com": ["104.42.195.92", "40.76.54.131"],
|
|
||||||
// DE doesn't talk to prod2 (main2) but it might be added
|
|
||||||
//"https://main2.documentdb.ext.azure.com": ["104.42.196.69"],
|
|
||||||
"https://main.documentdb.ext.azure.cn": ["139.217.8.252"],
|
|
||||||
"https://main.documentdb.ext.azure.us": ["52.244.48.71"],
|
|
||||||
// Add ussec and usnat when endpoint address is known:
|
|
||||||
//ussec: ["29.26.26.67", "29.26.26.66"],
|
|
||||||
//usnat: ["7.28.202.68"],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
||||||
"https://main.documentdb.ext.azure.com",
|
"https://main.documentdb.ext.azure.com",
|
||||||
"https://main.documentdb.ext.azure.cn",
|
"https://main.documentdb.ext.azure.cn",
|
||||||
@@ -78,7 +67,7 @@ export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localho
|
|||||||
|
|
||||||
export const allowedMongoBackendEndpoints: ReadonlyArray<string> = ["https://localhost:1234"];
|
export const allowedMongoBackendEndpoints: ReadonlyArray<string> = ["https://localhost:1234"];
|
||||||
|
|
||||||
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.microsoft.com"];
|
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.windows.net"];
|
||||||
|
|
||||||
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export function mockFunction<T extends (...args: any[]) => any>(fn: T): jest.MockedFunction<T> {
|
|
||||||
return fn as jest.MockedFunction<T>;
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import { resetConfigContext, updateConfigContext } from "ConfigContext";
|
|
||||||
import { DatabaseAccount, IpRule } from "Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "UserContext";
|
|
||||||
import { PortalBackendIPs } from "Utils/EndpointValidation";
|
|
||||||
import { getNetworkSettingsWarningMessage } from "./NetworkUtility";
|
|
||||||
|
|
||||||
describe("NetworkUtility tests", () => {
|
|
||||||
describe("getNetworkSettingsWarningMessage", () => {
|
|
||||||
const publicAccessMessagePart = "Please enable public access to proceed";
|
|
||||||
const accessMessagePart = "Please allow access from Azure Portal to proceed";
|
|
||||||
// validEnpoints are a subset of those from Utils/EndpointValidation/PortalBackendIPs
|
|
||||||
const validEndpoints = [
|
|
||||||
"https://main.documentdb.ext.azure.com",
|
|
||||||
"https://main.documentdb.ext.azure.cn",
|
|
||||||
"https://main.documentdb.ext.azure.us",
|
|
||||||
];
|
|
||||||
|
|
||||||
let warningMessageResult: string;
|
|
||||||
const warningMessageFunc = (msg: string) => (warningMessageResult = msg);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
warningMessageResult = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
resetConfigContext();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return no message when publicNetworkAccess is enabled", async () => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
properties: {
|
|
||||||
publicNetworkAccess: "Enabled",
|
|
||||||
},
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
await getNetworkSettingsWarningMessage(warningMessageFunc);
|
|
||||||
expect(warningMessageResult).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return publicAccessMessage when publicNetworkAccess is disabled", async () => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
properties: {
|
|
||||||
publicNetworkAccess: "Disabled",
|
|
||||||
},
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
await getNetworkSettingsWarningMessage(warningMessageFunc);
|
|
||||||
expect(warningMessageResult).toContain(publicAccessMessagePart);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should return no message when the appropriate ip rules are added to mongo/cassandra account per endpoint`, () => {
|
|
||||||
validEndpoints.forEach(async (endpoint) => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
kind: "MongoDB",
|
|
||||||
properties: {
|
|
||||||
ipRules: PortalBackendIPs[endpoint].map((ip: string) => ({ ipAddressOrRange: ip } as IpRule)),
|
|
||||||
publicNetworkAccess: "Enabled",
|
|
||||||
},
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateConfigContext({
|
|
||||||
BACKEND_ENDPOINT: endpoint,
|
|
||||||
});
|
|
||||||
|
|
||||||
let asyncWarningMessageResult: string;
|
|
||||||
const asyncWarningMessageFunc = (msg: string) => (asyncWarningMessageResult = msg);
|
|
||||||
|
|
||||||
await getNetworkSettingsWarningMessage(asyncWarningMessageFunc);
|
|
||||||
expect(asyncWarningMessageResult).toBeUndefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return accessMessage when incorrent ip rule is added to mongo/cassandra account per endpoint", () => {
|
|
||||||
validEndpoints.forEach(async (endpoint) => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
kind: "MongoDB",
|
|
||||||
properties: {
|
|
||||||
ipRules: [{ ipAddressOrRange: "1.1.1.1" }],
|
|
||||||
publicNetworkAccess: "Enabled",
|
|
||||||
},
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
|
|
||||||
updateConfigContext({
|
|
||||||
BACKEND_ENDPOINT: endpoint,
|
|
||||||
});
|
|
||||||
|
|
||||||
let asyncWarningMessageResult: string;
|
|
||||||
const asyncWarningMessageFunc = (msg: string) => (asyncWarningMessageResult = msg);
|
|
||||||
|
|
||||||
await getNetworkSettingsWarningMessage(asyncWarningMessageFunc);
|
|
||||||
expect(asyncWarningMessageResult).toContain(accessMessagePart);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Postgres and vcore mongo account checks basically pass through to CheckFirewallRules so those
|
|
||||||
// tests are omitted here and included in CheckFirewallRules.test.ts
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
import { configContext } from "ConfigContext";
|
|
||||||
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
import { checkFirewallRules } from "Explorer/Tabs/Shared/CheckFirewallRules";
|
||||||
import { userContext } from "UserContext";
|
import { userContext } from "UserContext";
|
||||||
import { PortalBackendIPs } from "Utils/EndpointValidation";
|
|
||||||
|
const PortalIPs: { [key: string]: string[] } = {
|
||||||
|
prod1: ["104.42.195.92", "40.76.54.131"],
|
||||||
|
prod2: ["104.42.196.69"],
|
||||||
|
mooncake: ["139.217.8.252"],
|
||||||
|
blackforest: ["51.4.229.218"],
|
||||||
|
fairfax: ["52.244.48.71"],
|
||||||
|
ussec: ["29.26.26.67", "29.26.26.66"],
|
||||||
|
usnat: ["7.28.202.68"],
|
||||||
|
};
|
||||||
|
|
||||||
export const getNetworkSettingsWarningMessage = async (
|
export const getNetworkSettingsWarningMessage = async (
|
||||||
setStateFunc: (warningMessage: string) => void
|
setStateFunc: (warningMessage: string) => void
|
||||||
@@ -20,7 +28,6 @@ export const getNetworkSettingsWarningMessage = async (
|
|||||||
setStateFunc,
|
setStateFunc,
|
||||||
accessMessage
|
accessMessage
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
} else if (userContext.apiType === "VCoreMongo") {
|
} else if (userContext.apiType === "VCoreMongo") {
|
||||||
checkFirewallRules(
|
checkFirewallRules(
|
||||||
"2023-03-01-preview",
|
"2023-03-01-preview",
|
||||||
@@ -31,7 +38,6 @@ export const getNetworkSettingsWarningMessage = async (
|
|||||||
setStateFunc,
|
setStateFunc,
|
||||||
accessMessage
|
accessMessage
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
} else if (accountProperties) {
|
} else if (accountProperties) {
|
||||||
// public network access is disabled
|
// public network access is disabled
|
||||||
if (
|
if (
|
||||||
@@ -39,14 +45,13 @@ export const getNetworkSettingsWarningMessage = async (
|
|||||||
accountProperties.publicNetworkAccess !== "SecuredByPerimeter"
|
accountProperties.publicNetworkAccess !== "SecuredByPerimeter"
|
||||||
) {
|
) {
|
||||||
setStateFunc(publicAccessMessage);
|
setStateFunc(publicAccessMessage);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipRules = accountProperties.ipRules;
|
const ipRules = accountProperties.ipRules;
|
||||||
// public network access is NOT set to "All networks"
|
// public network access is NOT set to "All networks"
|
||||||
if (ipRules?.length > 0) {
|
if (ipRules.length > 0) {
|
||||||
if (userContext.apiType === "Cassandra" || userContext.apiType === "Mongo") {
|
if (userContext.apiType === "Cassandra" || userContext.apiType === "Mongo") {
|
||||||
const portalIPs = PortalBackendIPs[configContext.BACKEND_ENDPOINT];
|
const portalIPs = PortalIPs[userContext.portalEnv];
|
||||||
let numberOfMatches = 0;
|
let numberOfMatches = 0;
|
||||||
ipRules.forEach((ipRule) => {
|
ipRules.forEach((ipRule) => {
|
||||||
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
|
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
|
||||||
|
|||||||
@@ -57,22 +57,4 @@ describe("shouldShowQueryPageOptions()", () => {
|
|||||||
});
|
});
|
||||||
expect(userContext.apiType).toBe("Mongo");
|
expect(userContext.apiType).toBe("Mongo");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be 'Postgres' for Postgres API", () => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
kind: "Postgres",
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
expect(userContext.apiType).toBe("Postgres");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should be 'VCoreMongo' for vCore Mongo", () => {
|
|
||||||
updateUserContext({
|
|
||||||
databaseAccount: {
|
|
||||||
kind: "VCoreMongo",
|
|
||||||
} as DatabaseAccount,
|
|
||||||
});
|
|
||||||
expect(userContext.apiType).toBe("VCoreMongo");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,7 +21,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 pbi-rdb-edog.analysis-df.windows.net" />
|
||||||
</customHeaders>
|
</customHeaders>
|
||||||
<redirectHeaders>
|
<redirectHeaders>
|
||||||
<clear />
|
<clear />
|
||||||
|
|||||||
Reference in New Issue
Block a user