Compare commits

..

2 Commits

Author SHA1 Message Date
Victor Meng
acd5974024 Hard code to always open old mongo shell 2022-12-07 10:21:08 -08:00
Victor Meng
22f5fc13b2 Empty commit to trigger new build 2022-11-14 12:42:07 -08:00
34 changed files with 394 additions and 692 deletions

View File

@@ -3,337 +3,337 @@
@import "../Common/Constants";
.query-panel {
display: table;
display: none;
width: 100%;
border-top: 1px solid #dddddd;
/*[{environment-commandbar-toolbar-separator}]*/
background-color: #ffffff;
/*[{plugin-background-color}]*/
padding: 2px 0px 0px 2px;
resize: vertical;
display: table;
display: none;
width: 100%;
border-top: 1px solid #DDDDDD;
/*[{environment-commandbar-toolbar-separator}]*/
background-color: #ffffff;
/*[{plugin-background-color}]*/
padding: 2px 0px 0px 2px;
resize: vertical;
}
.query-panel .row {
display: table-row;
display: table-row;
}
.query-panel .row .cell {
display: table-cell;
display: table-cell;
}
.query-panel.transition-in {
display: table;
top: 0px;
-webkit-transition: top 2s linear;
-ms-transition: top 2s linear;
-moz-transition: top 2s linear;
-khtml-transition: top 2s linear;
-o-transition: top 2s linear;
transition: top 2s linear;
display: table;
top: 0px;
-webkit-transition: top 2s linear;
-ms-transition: top 2s linear;
-moz-transition: top 2s linear;
-khtml-transition: top 2s linear;
-o-transition: top 2s linear;
transition: top 2s linear;
}
.query-builder {
width: 100%;
padding-right: @DefaultSpace;
border-bottom: 1px solid @BaseMedium;
margin-bottom: @DefaultSpace;
width:100%;
padding-right: @DefaultSpace;
border-bottom: 1px solid @BaseMedium;
margin-bottom: @DefaultSpace;
}
.query-builder-toolbar {
background-color: #ffffff;
/*[{plugin-background-color}]*/
min-width: 600px;
height: 30px;
border-bottom: 1px solid #dddddd;
/*[1px solid {environment-commandbar-toolbar-separator}]*/
background-color: #ffffff;
/*[{plugin-background-color}]*/
min-width: 600px;
height: 30px;
border-bottom: 1px solid #DDDDDD;
/*[1px solid {environment-commandbar-toolbar-separator}]*/
}
.query-builder-toolbar .query-toolbar-group {
display: inline-block;
height: 24px;
margin: 2px 0px;
vertical-align: middle;
display: inline-block;
height: 24px;
margin: 2px 0px;
vertical-align: middle;
}
.query-builder-toolbar .query-toolbar-group .query-toolbar-button {
min-width: 0px;
padding: 0px;
margin-left: 2px;
background-color: transparent;
border: solid transparent;
min-width: 0px;
padding: 0px;
margin-left: 2px;
background-color: transparent;
border: solid transparent;
}
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:active {
outline: 2px solid dodgerblue;
/*[2px solid {common-common-controls-button-border-hover}]*/
outline: 2px solid dodgerblue;
/*[2px solid {common-common-controls-button-border-hover}]*/
}
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:hover {
background-color: #cccedb;
/*[{common-controls-button-hover-background}]*/
background-color: #CCCEDB;
/*[{common-controls-button-hover-background}]*/
}
.query-builder-toolbar .query-toolbar-group .query-toolbar-button.active {
background-color: #e6e7ed;
/*[{common-controls-inner-tab-active-background}]*/
outline: none;
background-color: #E6E7ED;
/*[{common-controls-inner-tab-active-background}]*/
outline: none
}
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:disabled,
.query-builder-toolbar .query-toolbar-group .query-toolbar-button.disabled {
background-color: #ffffff;
/*[{common-controls-button-disabled-background}]*/
background: transparent;
border: 1px solid transparent;
outline: none;
opacity: 0.4;
background-color: #ffffff;
/*[{common-controls-button-disabled-background}]*/
background: transparent;
border: 1px solid transparent;
outline: none;
opacity: 0.4;
}
.tableContainer {
overflow: hidden;
.flex-display();
.flex-direction();
overflow: hidden;
.flex-display();
.flex-direction();
}
.tablesQueryTab {
padding-left: @MediumSpace;
width: 100%;
margin-bottom: @LargeSpace;
.tablesQueryTab{
padding-left: @MediumSpace;
width: 100%;
margin-bottom:@LargeSpace;
}
.entity-error-Img {
width: @WarningErrorIconSize;
height: @WarningErrorIconSize;
margin: @DefaultSpace 0px 0px @SmallSpace;
width: @WarningErrorIconSize;
height: @WarningErrorIconSize;
margin: @DefaultSpace 0px 0px @SmallSpace;
}
.query-editor-panel {
margin-right: 16px;
margin-left: 16px;
margin-top: 25px;
position: relative;
vertical-align: middle;
cursor: default;
margin-right: 16px;
margin-left: 16px;
margin-top: 25px;
position: relative;
vertical-align: middle;
cursor: default;
}
.query-editor-text {
width: 100%;
margin: 2px;
border: solid 1px #a9acb3;
/*[{plugin-textbox-disabled-color}]*/
resize: none;
margin-top: -39px;
background-color: #ddd;
padding: 5px;
width: 100%;
margin: 2px;
border: solid 1px #A9ACB3;
/*[{plugin-textbox-disabled-color}]*/
resize: none;
margin-top: -39px;
background-color: #ddd;
padding: 5px;
}
.error-bar {
padding: @LargeSpace 34px @MediumSpace 24px;
padding: @LargeSpace 34px @MediumSpace 24px;
}
.error-message {
background-color: @BaseLow;
padding: @DefaultSpace;
display: inline-flex;
background-color: @BaseLow;
padding: @DefaultSpace;
display: inline-flex;
}
.error-text {
padding-left: @MediumSpace;
padding-left: @MediumSpace;
}
.query-editor-text-invalid {
width: 100%;
margin: 2px;
border: 1px solid #e51400;
resize: none;
margin-top: -30px;
width: 100%;
margin: 2px;
border: 1px solid #e51400;
resize: none;
margin-top: -30px;
}
.query-editor-panel .warning-bar {
width: 100%;
height: 20px;
background-color: #ffffff;
/*[{plugin-background-color}]*/
position: absolute;
top: -24px;
width: 100%;
height: 20px;
background-color: #ffffff;
/*[{plugin-background-color}]*/
position: absolute;
top: -24px;
}
.query-editor-panel .warning-bar .warning-message {
display: inline-flex;
padding-top: 2px;
vertical-align: middle;
display: inline-flex;
padding-top: 2px;
vertical-align: middle;
}
.query-editor-panel .warning-bar .warning-message .warning-text {
margin-left: 2px;
margin-left: 2px;
}
.advanced-options-panel {
margin-bottom: @DefaultSpace;
.advanced-options-panel{
margin-bottom: @DefaultSpace;
}
.advanced-options-panel .advanced-heading .advanced-title {
display: inline-flex;
margin-left: 27px;
margin-top: 10px;
cursor: default;
display: inline-flex;
margin-left: 27px;
margin-top: 10px;
cursor: default;
}
.advanced-options-panel .advanced-options {
margin-left: 32px;
margin-top: 5px;
border: 1px solid transparent;
margin-left: 32px;
margin-top: 5px;
border: 1px solid transparent;
}
hr {
margin-top: 10px;
margin-bottom: 12px;
border: 0;
border-top: 1px solid #ccc;
margin-top: 10px;
margin-bottom: 12px;
border: 0;
border-top: 1px solid #ccc;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
-webkit-appearance: none;
}
.advanced-options-panel .advanced-options .top .top-input {
width: 100px;
word-spacing: normal;
color: #1e1e1e;
/*[{common-controls-button-foreground}]*/
border: 1px solid #cccedb;
/*[1px solid {plugin-textbox-border-color}]*/
height: 20px;
margin-left: 8px;
width: 100px;
word-spacing: normal;
color: #1E1E1E;
/*[{common-controls-button-foreground}]*/
border: 1px solid #CCCEDB;
/*[1px solid {plugin-textbox-border-color}]*/
height: 20px;
margin-left: 8px;
}
.advanced-options-panel .advanced-options .top .invalid-top {
color: red;
color: red;
}
.advanced-options-panel .advanced-options .select {
margin-top: 18px;
display: inline-flex;
margin-top: 18px;
display: inline-flex;
}
.advanced-options-icon {
margin-left: 2px;
vertical-align: sub;
margin-left: 2px;
vertical-align: sub;
}
.advanced-options-panel .advanced-options .select .select-options-text {
margin-left: 4px;
margin-left: 4px;
}
.advanced-options-panel .advanced-options .select .select-options-link {
margin-left: 4px;
cursor: pointer;
outline: none;
margin-left: 4px;
cursor: pointer;
outline: none;
}
.query-panel .row .column-headers .Field {
padding-left: 95px;
padding-right: 0px;
padding-bottom: 6px;
padding-left: 95px;
padding-right: 0px;
padding-bottom: 6px;
}
.clause-table {
border-spacing: 0px;
display: table;
width: 100%;
margin-top: -3px;
border-spacing: 0px;
display: table;
width: 100%;
margin-top: -3px;
}
.clause-table-row {
display: row;
margin-bottom: 10px;
display: row;
margin-bottom: 10px;
}
.clause-table-cell {
display: table-cell;
text-align: left;
vertical-align: middle;
display: table-cell;
text-align: left;
vertical-align: middle;
}
.action-column > button,
.group-control-header > button,
.group-indicator-column > button {
min-width: 20px;
width: 20px;
padding: 0px;
background-color: transparent;
border-color: transparent;
cursor: pointer;
.action-column>button,
.group-control-header>button,
.group-indicator-column>button {
min-width: 20px;
width: 20px;
padding: 0px;
background-color: transparent;
border-color: transparent;
cursor: pointer;
}
.group-control-header > button:disabled {
min-width: 20px;
width: 20px;
padding: 0px;
background-color: transparent;
border-color: transparent;
outline: none;
opacity: 0.4;
cursor: default;
.group-control-header>button:disabled {
min-width: 20px;
width: 20px;
padding: 0px;
background-color: transparent;
border-color: transparent;
outline: none;
opacity: 0.4;
cursor: default;
}
.clause-table-field {
width: 100%;
border: 1px solid #bbbbbb;
width: 100%;
border: 1px solid #bbbbbb;
}
.clause-table-cell button {
height: 20px;
height: 20px;
}
.clause-table-cell input[type="checkbox"] {
padding: 0px;
margin-bottom: 12px;
padding: 0px;
margin-bottom: 12px;
}
.and-or-svg {
margin-top: -8px;
margin-right: -5px;
margin-top: -8px;
margin-right: -5px;
}
.scroll-box {
border-bottom: 1px transparent #ddd;
/*[1px solid {plugin-table-border-color}]*/
border-top: 1px transparent #ddd;
/*[1px solid {plugin-table-border-color}]*/
max-height: 20vh;
width: 100%;
border-bottom: 1px transparent #DDD;
/*[1px solid {plugin-table-border-color}]*/
border-top: 1px transparent #DDD;
/*[1px solid {plugin-table-border-color}]*/
max-height: 20vh;
width: 100%;
}
.scrollable {
overflow: auto;
overflow-x: hidden;
overflow: auto;
overflow-x: hidden;
}
.and-or-column,
.and-or-header {
min-width: 65px;
padding-right: 10px;
padding-left: 5px;
min-width: 65px;
padding-right: 10px;
padding-left: 5px;
}
.operator-column,
.operator-header {
min-width: 65px;
padding-right: 10px;
min-width: 65px;
padding-right: 10px;
}
.field-header,
.field-column {
min-width: 125px;
padding-right: 10px;
min-width: 125px;
padding-right: 10px;
}
.type-header,
.type-column {
min-width: 85px;
min-width: 85px;
}
.and-or-column,
@@ -345,41 +345,41 @@ input::-webkit-inner-spin-button {
.type-header,
.type-column,
.action-header {
padding-right: 10px;
margin-bottom: 8px;
padding-right: 10px;
margin-bottom: 8px;
}
.value-header,
.value-column,
.time-column {
min-width: 230px;
padding: 0px 4px 0px 0px;
width: 100%;
margin-bottom: 8px;
min-width: 230px;
padding: 0px 4px 0px 0px;
width: 100%;
margin-bottom: 8px;
}
.group-control-header,
.group-control-column {
min-width: 25px;
text-align: right;
min-width: 25px;
text-align: right;
}
.group-indicator-table {
border-spacing: 0px;
min-height: 24px;
border-spacing: 0px;
min-height: 24px
}
.group-indicator-column {
min-width: 21px;
padding: 0px;
border-style: none;
height: 29px;
min-width: 21px;
padding: 0px;
border-style: none;
height: 29px;
}
.clause-table-cell.action-column,
.clause-table-cell.action-column,
.clause-table-cell.action-header {
min-width: 60px;
padding-left: @SmallSpace;
min-width: 60px;
padding-left: @SmallSpace;
}
.action-header,
@@ -388,14 +388,15 @@ input::-webkit-inner-spin-button {
.operator-header,
.value-header,
.and-or-header {
padding-right: 4px;
padding-bottom: 5px;
padding-right: 4px;
padding-bottom: 5px;
}
.header-background {
background-color: #ffffff;
background-color: #ffffff;
}
/*.type-header {
padding-right: 4px;
}
@@ -409,111 +410,112 @@ input::-webkit-inner-spin-button {
}*/
.clause-table-field[readonly] {
background-color: #eeeef2;
/*[{plugin-table-header-background-color}]*/
border: 1px solid #cccedb;
/*[{plugin-table-border-color}]*/
background-color: #EEEEF2;
/*[{plugin-table-header-background-color}]*/
border: 1px solid #CCCEDB;
/*[{plugin-table-border-color}]*/
}
.addClause-title {
/*[{common-common-controls-button-border-hover}]*/
cursor: pointer;
margin-left: -5px;
/*[{common-common-controls-button-border-hover}]*/
cursor: pointer;
margin-left: -5px;
}
.addClause {
width: 125px;
padding: 8px 0px 5px 5px;
border: 1px solid #fff;
margin-left: 5px;
width: 125px;
padding: 8px 0px 5px 5px;
border: 1px solid #fff;
margin-left: 5px;
}
.addClause:hover {
.hover();
.hover();
}
.addClause:active {
.active();
border: 1px dashed @AccentMedium;
.active();
border: 1px dashed @AccentMedium;
}
.clause-table-row {
min-width: 550px;
width: 100%;
min-width: 550px;
width: 100%;
}
.clause-table-field field-column {
min-width: 75px;
height: 30px;
width: 100%;
min-width: 75px;
height: 30px;
width: 100%;
}
.clause-table-field field-input {
min-width: 54px;
margin-left: -78px;
height: 25px;
border: none;
min-width: 54px;
margin-left: -78px;
height: 25px;
border: none;
}
.query-panel .row .spacing {
padding-bottom: 6px;
padding-bottom: 6px;
}
.query-panel .divider.horizontal {
height: 10px;
width: 100%;
height: 10px;
width: 100%
}
.inline-div {
display: inline;
display: inline
}
.querybuilder-addpropertyImg,
.querybuilder-cancelImg {
width: 14px;
height: 14px;
margin-left: 3px;
margin-bottom: 8px;
width: 14px;
height: 14px;
margin-left: 3px;
margin-bottom: 8px;
}
.addclauseProperty-Img {
width: 14px;
height: 14px;
margin-bottom: 5px;
margin-left: 12px;
width: 14px;
height: 14px;
margin-bottom: 5px;
margin-left: 12px;
}
.entity-Add-Cancel {
// padding: @DefaultSpace @SmallSpace @SmallSpace;
cursor: pointer;
padding: @DefaultSpace @SmallSpace @SmallSpace;
cursor: pointer;
}
.entity-Add-Cancel:hover {
.hover();
.hover();
}
.entity-Add-Cancel:active {
.active();
.active();
}
.query-builder-isDisabled {
border: 1px solid #cccedb;
color: #ccc;
border: 1px solid #CCCEDB;
color: #ccc;
}
.edit-value-text {
padding-left: @DefaultSpace;
padding-left: @DefaultSpace;
}
.expand-triangle {
width: 10px;
height: 10px;
width: 10px;
height: 10px;
}
.expand-triangle-right {
margin-bottom: 5px;
margin-bottom: 5px;
}
/*
@media only screen and (max-width: 1200px) {
.clause-table {
@@ -522,4 +524,4 @@ input::-webkit-inner-spin-button {
width: 100%;
padding-top: 10px;
}
}*/
}*/

View File

@@ -45,8 +45,6 @@ export class ArmResourceTypes {
export class BackendDefaults {
public static partitionKeyKind = "Hash";
public static partitionKeyMultiHash = "MultiHash";
public static maxNumMultiHashPartition = 2;
public static singlePartitionStorageInGb: string = "10";
public static multiPartitionStorageInGb: string = "100";
public static maxChangeFeedRetentionDuration: number = 10;

View File

@@ -73,17 +73,6 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
const sectionStackTokens: IStackTokens = { childrenGap: 12 };
const handleKeyPress = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
onEditEntity();
}
};
const handleKeyPressdelete = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
onDeleteEntity();
}
};
const getEntityValueType = (): string => {
const { Int, Smallint, Tinyint } = CassandraType;
const { Double, Int32, Int64 } = TableType;
@@ -137,28 +126,12 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
/>
{!isEntityValueDisable && (
<TooltipHost content="Edit property" id="editTooltip">
<Image
{...imageProps}
src={EditIcon}
alt="editEntity"
id="editEntity"
onClick={onEditEntity}
tabIndex={0}
onKeyPress={handleKeyPress}
/>
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
</TooltipHost>
)}
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
<TooltipHost content="Delete property" id="deleteTooltip">
<Image
{...imageProps}
src={DeleteIcon}
alt="delete entity"
id="deleteEntity"
onClick={onDeleteEntity}
tabIndex={0}
onKeyPress={handleKeyPressdelete}
/>
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
</TooltipHost>
)}
</Stack>

View File

@@ -9,7 +9,7 @@ export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }:
return (
<span>
<TooltipHost content={children}>
<Icon iconName="Info" ariaLabel={children} className="panelInfoIcon" tabIndex={0} />
<Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</span>
);

View File

@@ -4,7 +4,6 @@ import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationCons
import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const deleteDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<void> => {
const entityName: string = getEntityName();
@@ -14,7 +13,7 @@ export const deleteDocument = async (collection: CollectionBase, documentId: Doc
await client()
.database(collection.databaseId)
.container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId))
.item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.delete();
logConsoleInfo(`Successfully deleted ${entityName} ${documentId.id()}`);
} catch (error) {

View File

@@ -1,12 +0,0 @@
import { userContext } from "UserContext";
import DocumentId from "../../Explorer/Tree/DocumentId";
export const getPartitionKeyValue = (documentId: DocumentId) => {
if (userContext.apiType === "Tables" && documentId.partitionKeyValue?.length === 0) {
return "";
}
if (documentId.partitionKeyValue?.length === 0) {
return undefined;
}
return documentId.partitionKeyValue;
};

View File

@@ -6,7 +6,6 @@ import { HttpHeaders } from "../Constants";
import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const readDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<Item> => {
const entityName = getEntityName();
@@ -22,7 +21,8 @@ export const readDocument = async (collection: CollectionBase, documentId: Docum
const response = await client()
.database(collection.databaseId)
.container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId))
// use undefined if the partitionKeyValue is empty
.item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.read(options);
return response?.resource;

View File

@@ -6,7 +6,6 @@ import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationCons
import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const updateDocument = async (
collection: CollectionBase,
@@ -26,7 +25,7 @@ export const updateDocument = async (
const response = await client()
.database(collection.databaseId)
.container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId))
.item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.replace(newDocument, options);
logConsoleInfo(`Successfully updated ${entityName} ${documentId.id()}`);

View File

@@ -397,7 +397,6 @@ export interface DataExplorerInputsFrame {
defaultCollectionThroughput?: CollectionCreationDefaults;
isPostgresAccount?: boolean;
isReplica?: boolean;
clientIpAddress?: string;
// TODO: Update this param in the OSS extension to remove isFreeTier, isMarlinServerGroup, and make nodes a flat array instead of an nested array
connectionStringParams?: any;
flights?: readonly string[];

View File

@@ -85,11 +85,7 @@ export const createCollectionContextMenuButton = (
iconSrc: HostedTerminalIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
if (useNotebook.getState().isShellEnabled) {
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
} else {
selectedCollection && selectedCollection.onNewMongoShellClick();
}
selectedCollection && selectedCollection.onNewMongoShellClick();
},
label: useNotebook.getState().isShellEnabled ? "Open Mongo Shell" : "New Shell",
});

View File

@@ -1,5 +1,5 @@
import { HoverCard, HoverCardType, Icon, Label, Link, Stack } from "@fluentui/react";
import * as React from "react";
import { Icon, Label, Stack, HoverCard, HoverCardType, Link } from "@fluentui/react";
import { CodeOfConductEndpoints } from "../../../../Common/Constants";
import "./InfoComponent.less";
@@ -41,7 +41,7 @@ export class InfoComponent extends React.Component<InfoComponentProps> {
public render(): JSX.Element {
return (
<HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}>
<div className="infoPanelMain" tabIndex={0}>
<div className="infoPanelMain">
<Icon className="infoIconMain" iconName="Help" styles={{ root: { verticalAlign: "middle" } }} />
<Label className="infoLabelMain">Help</Label>
</div>

View File

@@ -12,7 +12,6 @@ exports[`InfoComponent renders 1`] = `
>
<div
className="infoPanelMain"
tabIndex={0}
>
<Icon
className="infoIconMain"

View File

@@ -310,9 +310,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
/>
)}
{userContext.apiType === "SQL" && this.isLargePartitionKeyEnabled() && (
<Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>
)}
{this.isLargePartitionKeyEnabled() && <Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>}
</Stack>
);

View File

@@ -82,6 +82,7 @@ interface ThroughputInputAutoPilotV3State {
spendAckChecked: boolean;
exceedFreeTierThroughput: boolean;
}
export class ThroughputInputAutoPilotV3Component extends React.Component<
ThroughputInputAutoPilotV3Props,
ThroughputInputAutoPilotV3State
@@ -623,10 +624,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
return (
<>
{warningMessage && (
<MessageBar
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
role="alert"
>
<MessageBar messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}>
{warningMessage}
</MessageBar>
)}

View File

@@ -15,7 +15,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
"iconName": "WarningSolid",
}
}
role="alert"
>
<Text
styles={

View File

@@ -23,12 +23,12 @@ describe("ThroughputInput Pane", () => {
});
it("should switch mode properly", () => {
wrapper.find('[aria-label="Manual database throughput"]').simulate("change");
wrapper.find('[aria-label="Manual mode"]').simulate("change");
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe(
"Container throughput (400 - unlimited RU/s)"
);
wrapper.find('[aria-label="Autoscale database throughput"]').simulate("change");
wrapper.find('[aria-label="Autoscale mode"]').simulate("change");
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe("Container throughput (autoscale)");
});
});

View File

@@ -186,9 +186,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<Stack horizontal verticalAlign="center">
<input
id="Autoscale-input"
className="throughputInputRadioBtn"
aria-label="Autoscale database throughput"
aria-label="Autoscale mode"
aria-required={true}
checked={isAutoscaleSelected}
type="radio"
@@ -196,14 +195,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Autoscale")}
/>
<label htmlFor="Autoscale-input" className="throughputInputRadioBtnLabel">
Autoscale
</label>
<span className="throughputInputRadioBtnLabel">Autoscale</span>
<input
id="Manual-input"
className="throughputInputRadioBtn"
aria-label="Manual database throughput"
aria-label="Manual mode"
checked={!isAutoscaleSelected}
type="radio"
aria-required={true}
@@ -211,20 +207,14 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Manual")}
/>
<label className="throughputInputRadioBtnLabel" htmlFor="Manual-input">
Manual
</label>
<span className="throughputInputRadioBtnLabel">Manual</span>
</Stack>
{isAutoscaleSelected && (
<Stack className="throughputInputSpacing">
<Text variant="small" aria-label="capacity calculator of azure cosmos db">
<Text variant="small" aria-label="ruDescription">
Estimate your required RU/s with{" "}
<Link
target="_blank"
href="https://cosmos.azure.com/capacitycalculator/"
aria-label="capacity calculator of azure cosmos db"
>
<Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/" aria-label="ruDescription">
capacity calculator
</Link>
.

View File

@@ -344,13 +344,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
onMouseLeave={[Function]}
>
<StyledIconBase
ariaLabel="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage."
ariaLabel="Info"
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
>
<IconBase
ariaLabel="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage."
ariaLabel="Info"
className="panelInfoIcon"
iconName="Info"
styles={[Function]}
@@ -630,7 +630,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
}
>
<i
aria-label="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage."
aria-label="Info"
className="panelInfoIcon root-57"
data-icon-name="Info"
role="img"
@@ -655,43 +655,39 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
className="ms-Stack css-58"
>
<input
aria-label="Autoscale database throughput"
aria-label="Autoscale mode"
aria-required={true}
checked={true}
className="throughputInputRadioBtn"
id="Autoscale-input"
key=".0:$.0"
onChange={[Function]}
role="radio"
tabIndex={0}
type="radio"
/>
<label
<span
className="throughputInputRadioBtnLabel"
htmlFor="Autoscale-input"
key=".0:$.1"
>
Autoscale
</label>
</span>
<input
aria-label="Manual database throughput"
aria-label="Manual mode"
aria-required={true}
checked={false}
className="throughputInputRadioBtn"
id="Manual-input"
key=".0:$.2"
onChange={[Function]}
role="radio"
tabIndex={0}
type="radio"
/>
<label
<span
className="throughputInputRadioBtnLabel"
htmlFor="Manual-input"
key=".0:$.3"
>
Manual
</label>
</span>
</div>
</Stack>
<Stack
@@ -701,23 +697,23 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
className="ms-Stack throughputInputSpacing css-59"
>
<Text
aria-label="capacity calculator of azure cosmos db"
aria-label="ruDescription"
key=".0:$.0"
variant="small"
>
<span
aria-label="capacity calculator of azure cosmos db"
aria-label="ruDescription"
className="css-54"
>
Estimate your required RU/s with
<StyledLinkBase
aria-label="capacity calculator of azure cosmos db"
aria-label="ruDescription"
href="https://cosmos.azure.com/capacitycalculator/"
target="_blank"
>
<LinkBase
aria-label="capacity calculator of azure cosmos db"
aria-label="ruDescription"
href="https://cosmos.azure.com/capacitycalculator/"
styles={[Function]}
target="_blank"
@@ -996,7 +992,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
}
>
<a
aria-label="capacity calculator of azure cosmos db"
aria-label="ruDescription"
className="ms-Link root-60"
href="https://cosmos.azure.com/capacitycalculator/"
onClick={[Function]}
@@ -1335,13 +1331,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
onMouseLeave={[Function]}
>
<StyledIconBase
ariaLabel="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage."
ariaLabel="Info"
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
>
<IconBase
ariaLabel="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage."
ariaLabel="Info"
className="panelInfoIcon"
iconName="Info"
styles={[Function]}
@@ -1621,7 +1617,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
}
>
<i
aria-label="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage."
aria-label="Info"
className="panelInfoIcon root-57"
data-icon-name="Info"
role="img"

View File

@@ -133,6 +133,7 @@ describe("ContainerSampleGenerator", () => {
} as DatabaseAccount,
});
// Rejects with error that contains experience
expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience);
});

View File

@@ -166,11 +166,7 @@ export function createContextCommandBarButtons(
iconAlt: label,
onCommandClick: () => {
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
if (useNotebook.getState().isShellEnabled) {
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
} else {
selectedCollection && selectedCollection.onNewMongoShellClick();
}
selectedCollection && selectedCollection.onNewMongoShellClick();
},
commandButtonLabel: label,
ariaLabel: label,

View File

@@ -89,10 +89,9 @@ export interface AddCollectionPanelState {
enableIndexing: boolean;
isSharded: boolean;
partitionKey: string;
subPartitionKeys: string[];
enableDedicatedThroughput: boolean;
createMongoWildCardIndex: boolean;
useHashV1: boolean;
useHashV2: boolean;
enableAnalyticalStore: boolean;
uniqueKeys: string[];
errorMessage: string;
@@ -122,11 +121,10 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
enableIndexing: true,
isSharded: userContext.apiType !== "Tables",
partitionKey: this.getPartitionKey(),
subPartitionKeys: [],
enableDedicatedThroughput: false,
createMongoWildCardIndex:
isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport"),
useHashV1: false,
useHashV2: false,
enableAnalyticalStore: false,
uniqueKeys: [],
errorMessage: "",
@@ -262,14 +260,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
true
).toLocaleLowerCase()}.`}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`A database is analogous to a namespace. It is the unit of management for a set of ${getCollectionName(
true
).toLocaleLowerCase()}.`}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -345,14 +336,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
true
).toLocaleLowerCase()} within the database.`}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`Throughput configured at the database level will be shared across all ${getCollectionName(
true
).toLocaleLowerCase()} within the database.`}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
)}
@@ -400,12 +384,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge}
content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -488,14 +467,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
"Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data."
}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={
"Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data."
}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -542,12 +514,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge}
content={this.getPartitionKeyTooltipText()}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={this.getPartitionKeyTooltipText()}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -579,77 +546,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
}
}}
/>
{userContext.apiType === "SQL" &&
this.state.subPartitionKeys.map((subPartitionKey: string, index: number) => {
return (
<Stack style={{ marginBottom: 8 }} key={`uniqueKey${index}`} horizontal>
<div
style={{
width: "20px",
border: "solid",
borderWidth: "0px 0px 1px 1px",
marginRight: "5px",
}}
></div>
<input
type="text"
id="addCollection-partitionKeyValue"
key={`addCollection-partitionKeyValue_${index}`}
aria-required
required
size={40}
tabIndex={index > 0 ? 1 : 0}
className="panelTextField"
autoComplete="off"
placeholder={this.getPartitionKeyPlaceHolder(index)}
aria-label={this.getPartitionKeyName()}
pattern={".*"}
title={""}
value={subPartitionKey}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
const subPartitionKeys = [...this.state.subPartitionKeys];
if (!this.state.subPartitionKeys[index] && !event.target.value.startsWith("/")) {
subPartitionKeys[index] = "/" + event.target.value.trim();
this.setState({ subPartitionKeys });
} else {
subPartitionKeys[index] = event.target.value.trim();
this.setState({ subPartitionKeys });
}
}}
/>
<IconButton
iconProps={{ iconName: "Delete" }}
style={{ height: 27 }}
onClick={() => {
const subPartitionKeys = this.state.subPartitionKeys.filter((uniqueKey, j) => index !== j);
this.setState({ subPartitionKeys });
}}
/>
</Stack>
);
})}
{userContext.apiType === "SQL" && (
<Stack className="panelGroupSpacing">
<DefaultButton
styles={{ root: { padding: 0, width: 250, height: 30 }, label: { fontSize: 12 } }}
hidden={this.state.useHashV1}
disabled={this.state.subPartitionKeys.length >= Constants.BackendDefaults.maxNumMultiHashPartition}
onClick={() => this.setState({ subPartitionKeys: [...this.state.subPartitionKeys, ""] })}
>
Add hierarchical partition key (preview)
</DefaultButton>
{this.state.subPartitionKeys.length > 0 && (
<Text variant="small">
<Icon iconName="InfoSolid" className="removeIcon" tabIndex={0} /> This feature allows you to
partition your data with up to three levels of keys for better data distribution. Requires preview
version of .NET V3 or Java V4 SDK.{" "}
<Link href="https://aka.ms/cosmos-hierarchical-partitioning" target="_blank">
Learn more
</Link>
</Text>
)}
</Stack>
)}
</Stack>
)}
@@ -676,17 +572,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
does not count towards the throughput you provisioned for the database. This throughput amount will be
billed in addition to the throughput amount you provisioned at the database level.`}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`You can optionally provision dedicated throughput for a ${getCollectionName().toLocaleLowerCase()} within a database that has throughput
provisioned. This dedicated throughput amount will not be shared with other ${getCollectionName(
true
).toLocaleLowerCase()} in the database and
does not count towards the throughput you provisioned for the database. This throughput amount will be
billed in addition to the throughput amount you provisioned at the database level.`}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
)}
@@ -717,18 +603,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</Text>
<TooltipHost
directionalHint={DirectionalHint.bottomLeftEdge}
content={
"Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key."
}
content="Unique keys provide developers with the ability to add a layer of data integrity to their database. By
creating a unique key policy when a container is created, you ensure the uniqueness of one or more values
per partition key."
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={
"Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key."
}
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -791,13 +670,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge}
content={this.getAnalyticalStorageTooltipContent()}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel="Enable analytical store capability to perform near real-time analytics on your operational data, without
impacting the performance of transactional workloads."
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -874,12 +747,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge}
content="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
/>
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost>
</Stack>
@@ -899,29 +767,18 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
)}
{userContext.apiType === "SQL" && (
<Stack className="panelGroupSpacing">
<Checkbox
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)"
checked={this.state.useHashV1}
styles={{
text: { fontSize: 12 },
checkbox: { width: 12, height: 12 },
label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" },
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ useHashV1: isChecked, subPartitionKeys: [] })
}
/>
<Text variant="small">
<Icon iconName="InfoSolid" className="removeIcon" tabIndex={0} /> To ensure compatibility with
older SDKs, the created container will use a legacy partitioning scheme that supports partition
key values of size only up to 101 bytes. If this is enabled, you will not be able to use
hierarchical partition keys.{" "}
<Link href="https://aka.ms/cosmos-large-pk" target="_blank">
Learn more
</Link>
</Text>
</Stack>
<Checkbox
label="My partition key is larger than 101 bytes"
checked={this.state.useHashV2}
styles={{
text: { fontSize: 12 },
checkbox: { width: 12, height: 12 },
label: { padding: 0, alignItems: "center" },
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ useHashV2: isChecked })
}
/>
)}
</Stack>
</CollapsibleSectionComponent>
@@ -976,20 +833,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName;
}
private getPartitionKeyPlaceHolder(index?: number): string {
private getPartitionKeyPlaceHolder(): string {
switch (userContext.apiType) {
case "Mongo":
return "e.g., address.zipCode";
case "Gremlin":
return "e.g., /address";
case "SQL":
return `${
index === undefined
? "Required - first partition key e.g., /TenantId"
: index === 0
? "second partition key e.g., /UserId"
: "third partition key e.g., /SessionId"
}`;
default:
return "e.g., /address/zipCode";
}
@@ -1315,16 +1164,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
}
const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys();
const partitionKeyVersion = this.state.useHashV1 ? undefined : 2;
const partitionKeyVersion = this.state.useHashV2 ? 2 : undefined;
const partitionKey: DataModels.PartitionKey = partitionKeyString
? {
paths: [
partitionKeyString,
...(userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0
? this.state.subPartitionKeys
: []),
],
kind: userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? "MultiHash" : "Hash",
paths: [partitionKeyString],
kind: "Hash",
version: partitionKeyVersion,
}
: undefined;

View File

@@ -89,8 +89,8 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
}
} catch (error) {
setLoadingFalse();
setFormError(error);
const errorMessage = getErrorMessage(error);
setFormError(errorMessage);
TelemetryProcessor.traceFailure(
Action.DeleteDatabase,
{

View File

@@ -48,7 +48,7 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
)}
</Text>
{showErrorDetails && (
<a className="paneErrorLink" role="link" onClick={expandConsole} tabIndex={0} onKeyPress={expandConsole}>
<a className="paneErrorLink" role="link" onClick={expandConsole}>
More details
</a>
)}

View File

@@ -242,11 +242,6 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
submitButtonText: getButtonLabel(userContext.apiType),
onSubmit,
};
const handlekeypressaddentity = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
addNewEntity();
}
};
return (
<RightPaneForm {...props}>
@@ -289,13 +284,7 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
);
})}
{userContext.apiType !== "Cassandra" && (
<Stack
horizontal
onClick={addNewEntity}
className="addButtonEntiy"
tabIndex={0}
onKeyPress={handlekeypressaddentity}
>
<Stack horizontal onClick={addNewEntity} className="addButtonEntiy">
<Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" />
<Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text>
</Stack>

View File

@@ -29,14 +29,10 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
className="addButtonEntiy"
horizontal={true}
onClick={[Function]}
onKeyPress={[Function]}
tabIndex={0}
>
<div
className="ms-Stack addButtonEntiy css-53"
onClick={[Function]}
onKeyPress={[Function]}
tabIndex={0}
>
<StyledImageBase
alt="Add Entity"

View File

@@ -31,7 +31,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="A database is analogous to a namespace. It is the unit of management for a set of containers."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -125,7 +124,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="Throughput configured at the database level will be shared across all containers within the database."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -165,7 +163,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="Unique identifier for the container and used for id-based routing through REST and all SDKs."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -209,7 +206,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="The partition key is used to automatically distribute data across partitions for scalability. Choose a property in your JSON document that has a wide range of values and evenly distributes request volume. For small read-heavy workloads or write-heavy workloads of any size, id is often a good choice."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -227,36 +223,13 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
id="addCollection-partitionKeyValue"
onChange={[Function]}
pattern=".*"
placeholder="Required - first partition key e.g., /TenantId"
placeholder="e.g., /address/zipCode"
required={true}
size={40}
title=""
type="text"
value=""
/>
<Stack
className="panelGroupSpacing"
>
<CustomizedDefaultButton
disabled={false}
hidden={false}
onClick={[Function]}
styles={
Object {
"label": Object {
"fontSize": 12,
},
"root": Object {
"height": 30,
"padding": 0,
"width": 250,
},
}
}
>
Add hierarchical partition key (preview)
</CustomizedDefaultButton>
</Stack>
</Stack>
<Stack>
<Stack
@@ -273,7 +246,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -331,7 +303,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4}
>
<Icon
ariaLabel="Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
@@ -425,49 +396,26 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
className="panelGroupSpacing"
id="collapsibleSectionContent"
>
<Stack
className="panelGroupSpacing"
>
<StyledCheckboxBase
checked={false}
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)"
onChange={[Function]}
styles={
Object {
"checkbox": Object {
"height": 12,
"width": 12,
},
"label": Object {
"alignItems": "center",
"padding": 0,
"whiteSpace": "break-spaces",
"wordWrap": "break-word",
},
"text": Object {
"fontSize": 12,
},
}
<StyledCheckboxBase
checked={false}
label="My partition key is larger than 101 bytes"
onChange={[Function]}
styles={
Object {
"checkbox": Object {
"height": 12,
"width": 12,
},
"label": Object {
"alignItems": "center",
"padding": 0,
},
"text": Object {
"fontSize": 12,
},
}
/>
<Text
variant="small"
>
<Icon
className="removeIcon"
iconName="InfoSolid"
tabIndex={0}
/>
To ensure compatibility with older SDKs, the created container will use a legacy partitioning scheme that supports partition key values of size only up to 101 bytes. If this is enabled, you will not be able to use hierarchical partition keys.
<StyledLinkBase
href="https://aka.ms/cosmos-large-pk"
target="_blank"
>
Learn more
</StyledLinkBase>
</Text>
</Stack>
}
/>
</Stack>
</CollapsibleSectionComponent>
</div>

View File

@@ -9,7 +9,7 @@ import {
Stack,
TeachingBubble,
TeachingBubbleContent,
Text
Text,
} from "@fluentui/react";
import { sendMessage } from "Common/MessageHandler";
import { MessageTypes } from "Contracts/ExplorerContracts";
@@ -528,7 +528,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
>
{item.title}
</Link>
<Image src={LinkIcon} alt=" " />
<Image src={LinkIcon} />
</Stack>
<Text>{item.description}</Text>
</Stack>

View File

@@ -516,7 +516,7 @@ export default class QueryBuilderViewModel {
};
public onAddNewClauseKeyDown = (event: KeyboardEvent): boolean => {
if (event.key === "Enter" || event.key === "Space") {
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.addClauseIndex(this.clauseArray().length - 1);
event.stopPropagation();
return false;

View File

@@ -70,19 +70,24 @@
<tbody data-bind="template: { name: 'queryClause-template', foreach: clauseArray, as: 'clause' }"></tbody>
</table>
</div>
<button
data-bind="click: addNewClause, event: { keydown: onAddNewClauseKeyDown }"
style="border: none; background: none"
<div
class="addClause"
role="button"
data-bind="click: addNewClause, event: { keydown: onAddNewClauseKeyDown }, attr: { title: addNewClauseLine }"
tabindex="0"
>
<div class="addClause" data-bind=" ">
<div class="addClause-heading">
<span class="clause-table addClause-title">
<img class="addclauseProperty-Img" style="margin-bottom: 5px" src="/Add-property.svg" />
<span style="margin-left: 5px" data-bind="text: addNewClauseLine"></span>
</span>
</div>
<div class="addClause-heading">
<span class="clause-table addClause-title">
<img
class="addclauseProperty-Img"
style="margin-bottom: 5px"
src="/Add-property.svg"
alt="Add new clause"
/>
<span style="margin-left: 5px" data-bind="text: addNewClauseLine"></span>
</span>
</div>
</button>
</div>
</div>
</div>
<!-- Tables Query Tab Query Helper - End-->
@@ -163,20 +168,22 @@
<script type="text/html" id="queryClause-template">
<tr class="clause-table-row">
<td class="clause-table-cell action-column">
<button
<span
class="entity-Add-Cancel"
role="button"
tabindex="0"
data-bind="click: $parent.addClauseIndex.bind($data, $index()), event: { keydown: $parent.onAddClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.insertNewFilterLine}"
>
<span class="entity-Add-Cancel" role="button">
<img class="querybuilder-addpropertyImg" src="/Add-property.svg" alt="Add clause" />
</span>
</button>
<button
<img class="querybuilder-addpropertyImg" src="/Add-property.svg" alt="Add clause" />
</span>
<span
class="entity-Add-Cancel"
role="button"
tabindex="0"
data-bind="hasFocus: isDeleteButtonFocused, click: $parent.deleteClause.bind($data, $index()), event: { keydown: $parent.onDeleteClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.removeThisFilterLine}"
>
<span class="entity-Add-Cancel" role="button">
<img class="querybuilder-cancelImg" src="/Entity_cancel.svg" alt="Delete clause" />
</span>
</button>
<img class="querybuilder-cancelImg" src="/Entity_cancel.svg" alt="Delete clause" />
</span>
</td>
<td class="clause-table-cell group-control-column">
<input type="checkbox" aria-label="And/Or" data-bind="checked: checkedForGrouping" />

View File

@@ -24,21 +24,22 @@ interface TabsProps {
}
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
const { openedTabs, openedReactTabs, activeTab, activeReactTab, networkSettingsWarning } = useTabs();
const { openedTabs, openedReactTabs, activeTab, activeReactTab, showNetworkSettingsWarning } = useTabs();
return (
<div className="tabsManagerContainer">
{networkSettingsWarning && (
{showNetworkSettingsWarning && (
<MessageBar
messageBarType={MessageBarType.warning}
actions={
<MessageBarButton onClick={() => sendMessage({ type: MessageTypes.OpenPostgresNetworkingBlade })}>
<MessageBarButton onClick={() => sendMessage({ type: MessageTypes.OpenCosmosDBNetworkingBlade })}>
Change network settings
</MessageBarButton>
}
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
>
{networkSettingsWarning}
The Network settings for this account are preventing access from Data Explorer. Please allow access from Azure
Portal to proceed.
</MessageBar>
)}
<div id="content" className="flexContainer hideOverflows">

View File

@@ -29,7 +29,6 @@ export type Features = {
readonly mongoProxyEndpoint?: string;
readonly mongoProxyAPIs?: string;
readonly enableThroughputCap: boolean;
readonly enableHierarchicalKeys: boolean;
// can be set via both flight and feature flag
autoscaleDefault: boolean;
@@ -91,7 +90,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
notebooksDownBanner: "true" === get("notebooksDownBanner"),
enableThroughputCap: "true" === get("enablethroughputcap"),
enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"),
};
}

View File

@@ -10,43 +10,31 @@ const PortalIPs: { [key: string]: string[] } = {
usnat: ["7.28.202.68"],
};
export const getNetworkSettingsWarningMessage = (clientIpAddress: string): string => {
export const doNetworkSettingsAllowDataExplorerAccess = (): boolean => {
const accountProperties = userContext.databaseAccount?.properties;
if (!accountProperties) {
return "";
return false;
}
// public network access is disabled
if (accountProperties.publicNetworkAccess !== "Enabled") {
return "The Network settings for this account are preventing access from Data Explorer. Please enable public access to proceed.";
return false;
}
const ipRules = accountProperties.ipRules;
// public network access is set to "All networks"
if (ipRules.length === 0) {
return "";
return true;
}
if (userContext.apiType === "Cassandra" || userContext.apiType === "Mongo") {
const portalIPs = PortalIPs[userContext.portalEnv];
let numberOfMatches = 0;
ipRules.forEach((ipRule) => {
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
numberOfMatches++;
}
});
if (numberOfMatches !== portalIPs.length) {
return "The Network settings for this account are preventing access from Data Explorer. Please allow access from Azure Portal to proceed.";
const portalIPs = PortalIPs[userContext.portalEnv];
let numberOfMatches = 0;
ipRules.forEach((ipRule) => {
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
numberOfMatches++;
}
});
return "";
} else {
if (!clientIpAddress || ipRules.some((ipRule) => ipRule.ipAddressOrRange === clientIpAddress)) {
return "";
}
return "The Network settings for this account are preventing access from Data Explorer. Please add your current IP to the firewall rules to proceed.";
}
return numberOfMatches === portalIPs.length;
};

View File

@@ -1,6 +1,6 @@
import { ReactTabKind, useTabs } from "hooks/useTabs";
import { useEffect, useState } from "react";
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
import { doNetworkSettingsAllowDataExplorerAccess } from "Utils/NetworkUtility";
import { applyExplorerBindings } from "../applyExplorerBindings";
import { AuthType } from "../AuthType";
import { AccountKind, Flights } from "../Common/Constants";
@@ -382,8 +382,8 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
}
}
const warningMessage = getNetworkSettingsWarningMessage(inputs.clientIpAddress);
useTabs.getState().setNetworkSettingsWarning(warningMessage);
const isDataExplorerAccessAllowed = doNetworkSettingsAllowDataExplorerAccess();
useTabs.getState().setShowNetworkSettingsWarning(!isDataExplorerAccessAllowed);
if (inputs.features) {
Object.assign(userContext.features, extractFeatures(new URLSearchParams(inputs.features)));

View File

@@ -9,7 +9,7 @@ interface TabsState {
openedReactTabs: ReactTabKind[];
activeTab: TabsBase | undefined;
activeReactTab: ReactTabKind | undefined;
networkSettingsWarning: string;
showNetworkSettingsWarning: boolean;
activateTab: (tab: TabsBase) => void;
activateNewTab: (tab: TabsBase) => void;
activateReactTab: (tabkind: ReactTabKind) => void;
@@ -21,7 +21,7 @@ interface TabsState {
closeAllNotebookTabs: (hardClose: boolean) => void;
openAndActivateReactTab: (tabKind: ReactTabKind) => void;
closeReactTab: (tabKind: ReactTabKind) => void;
setNetworkSettingsWarning: (warningMessage: string) => void;
setShowNetworkSettingsWarning: (showWarning: boolean) => void;
}
export enum ReactTabKind {
@@ -35,7 +35,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
openedReactTabs: [ReactTabKind.Home],
activeTab: undefined,
activeReactTab: ReactTabKind.Home,
networkSettingsWarning: "",
showNetworkSettingsWarning: false,
activateTab: (tab: TabsBase): void => {
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
set({ activeTab: tab, activeReactTab: undefined });
@@ -145,5 +145,5 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
set({ openedReactTabs: updatedOpenedReactTabs });
},
setNetworkSettingsWarning: (warningMessage: string) => set({ networkSettingsWarning: warningMessage }),
setShowNetworkSettingsWarning: (showWarning: boolean) => set({ showNetworkSettingsWarning: showWarning }),
}));