Compare commits

..

4 Commits

Author SHA1 Message Date
Chris-MS-896
417a6151be Merge branch 'master' into v-yiqcao/throughoutValidation 2020-12-31 18:59:42 -06:00
Chris-MS-896
3c25788e72 'minor change' 2020-12-22 22:11:24 -06:00
Chris-MS-896
1c8deb1fcc no message 2020-12-22 21:53:28 -06:00
artrejo
4664038df0 Add onChange event to throughput text field 2020-12-22 16:59:50 -08:00
34 changed files with 2117 additions and 2421 deletions

View File

@@ -3,8 +3,8 @@
/******************************************************************************/
@font-face {
font-family: wf_segoe-ui_normal;
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff");
font-family: wf_segoe-ui_normal;
src: url('../../fonts/segoe-ui/west-european/normal/latest.woff');
}
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
@@ -20,26 +20,26 @@
COLORS
/******************************************************************************/
@AccentMediumHigh: #0058ad;
@AccentMedium: #004e87;
@AccentHigh: #1ebaed;
@AccentExtraHigh: #55b3ff;
@AccentLow: #edf6ff;
@AccentMediumLow: #ddeefe;
@AccentLight: #eef7ff;
@AccentExtra: #ddf0ff;
@AccentMediumHigh: #0058AD;
@AccentMedium: #004E87;
@AccentHigh: #1EBAED;
@AccentExtraHigh: #55B3FF;
@AccentLow: #EDF6FF;
@AccentMediumLow: #DDEEFE;
@AccentLight: #EEF7FF;
@AccentExtra: #DDF0FF;
@SelectionHigh: #b91f26;
@BaseLight: #ffffff;
@SelectionHigh: #B91F26;
@BaseLight: #FFFFFF;
@BaseDark: #000000;
@NotificationLow: #fff4ce;
@NotificationHigh: #f9e9b0;
@Purple1: #8a2da5;
@NotificationLow: #FFF4CE;
@NotificationHigh: #F9E9B0;
@Purple1: #8A2DA5;
@Dirty: #9b4f96;
@BaseLow: #f2f2f2;
@BaseMediumLow: #e6e6e6;
@BaseMedium: #cccccc;
@BaseLow: #F2F2F2;
@BaseMediumLow: #E6E6E6;
@BaseMedium: #CCCCCC;
@BaseMediumHigh: #767676;
@BaseHigh: #393939;
@@ -53,7 +53,7 @@
@ErrorColor: @SelectionHigh;
@SelectionColor: #3074b0;
@SelectionColor: #3074B0;
@FocusColor: #605e5c;
@@ -80,7 +80,7 @@
@ImgWidth: 14px;
@ImgHeight: 14px;
@toggleFontWeight: 700;
@toggleFontWeight:700;
//Resource Tree
@TreeLineHeight: 17px;
@@ -144,16 +144,16 @@
/**********************************************************************************/
.flex-display(@display: flex) {
display: ~"-webkit-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
display: ~"-webkit-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
}
.flex-direction(@direction: column) {
-webkit-flex-direction: @direction;
-ms-flex-direction: @direction;
flex-direction: @direction;
-ms-flex-direction: @direction;
flex-direction: @direction;
}
/*************************************************************************************
@@ -161,31 +161,32 @@
**************************************************************************************/
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.selectedRadio,
.selectedRadio:hover,
.selectedRadio:active,
.selectedRadio.dirty,
.tab [type="radio"]:checked ~ label,
.tab [type="radio"]:checked ~ label:hover {
-ms-high-contrast-adjust: none;
-webkit-text-fill-color: HighlightText;
color: HighlightText;
border-color: HighlightText;
background-color: Highlight;
}
.queryMetricsSummaryTuple {
th,
td {
&:nth-child(2) {
width: @IETableDataWidth;
}
&:nth-child(3) {
width: 50%;
}
.selectedRadio,
.selectedRadio:hover,
.selectedRadio:active,
.selectedRadio.dirty,
.tab [type=radio]:checked ~ label,
.tab [type=radio]:checked ~ label:hover {
-ms-high-contrast-adjust: none;
-webkit-text-fill-color: HighlightText;
color: HighlightText;
border-color: HighlightText;
background-color: Highlight;
}
.queryMetricsSummaryTuple {
th, td {
&:nth-child(2) {
width: @IETableDataWidth;
}
&:nth-child(3) {
width: 50%;
}
}
}
}
}
/********************************************************************************************
@@ -193,15 +194,15 @@
*********************************************************************************************/
.hover() {
background-color: @AccentLight;
background-color: @AccentLight;
}
.active() {
background-color: @AccentExtra;
background-color: @AccentExtra;
}
.focus() {
outline: 1px dashed @FocusColor;
outline: 1px dashed @FocusColor;
}
/************************************************************************************************
@@ -211,87 +212,63 @@
@ToggleWidth: 180px;
.toggleSwitch() {
max-width: 100%;
margin-bottom: @SmallSpace;
padding: @SmallSpace;
cursor: pointer;
color: @BaseHigh;
font-weight: 400;
font-size: @mediumFontSize;
font-family: @DataExplorerFont;
max-width: 100%;
margin-bottom: @SmallSpace;
padding: @SmallSpace;
cursor: pointer;
color: @BaseHigh;
font-weight: 400;
font-size: @mediumFontSize;
font-family: @DataExplorerFont;
}
.selectedToggle() {
border-bottom: 2px solid @BaseHigh;
border-bottom: 2px solid @BaseHigh;
}
.unselectedToggle() {
color: @AccentMediumHigh;
color: @AccentMediumHigh;
}
/********************************************************************************************************
Common Data Explorer Icons
*********************************************************************************************************/
.dataExplorerIcons() {
cursor: pointer;
width: @ImgWidth;
height: @ImgHeight;
cursor: pointer;
width: @ImgWidth;
height: @ImgHeight;
}
/*********************************************************************************************************
Info Tooltip
**********************************************************************************************************/
.infoTooltip() {
position: relative;
display: inline-block;
position: relative;
display: inline-block;
}
.tooltipText(@textColor: @BaseLight, @backgroundColor: @BaseHigh) {
visibility: hidden;
background-color: @backgroundColor;
color: @textColor;
position: absolute;
z-index: 1;
left: @MediumSpace;
padding: @MediumSpace;
visibility: hidden;
background-color: @backgroundColor;
color: @textColor;
position: absolute;
z-index: 1;
left: @MediumSpace;
padding: @MediumSpace;
}
.tooltipTextAfter(@color: @BaseDark) {
content: "";
position: absolute;
right: 100%;
border-style: solid;
border-color: transparent @color transparent transparent;
left: 0px;
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
content: "";
position: absolute;
right: 100%;
border-style: solid;
border-color: transparent @color transparent transparent;
left: 0px;
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
}
.tooltipVisible() {
visibility: visible;
}
.inputTooltip() {
position: relative;
}
.inputTooltipText(@textColor: @BaseLight, @backgroundColor: @BaseHigh) {
background-color: @backgroundColor;
color: @textColor;
position: absolute;
z-index: 1;
padding: @MediumSpace;
}
.inputTooltipTextAfter(@color: @BaseDark) {
content: "";
position: absolute;
right: 100%;
border-style: solid;
border-color: transparent @color transparent transparent;
left: 10px;
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
visibility: visible;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,20 @@
@import "./Common/Constants";
.main {
width: 100%;
float: left;
transition: all .0s ease-in-out;
-ms-transition: all 0s ease-in-out;
-webkit-transition: all 0s ease-in-out;
-moz-transition: all .0s ease-in-out;
height: 100%;
background-color: white;
border-left: 0px solid white;
}
.resourceTree {
height: 100%;
flex: 0 0 auto;
.main {
height: 100%;
}
}
.resourceTreeScroll {

View File

@@ -132,7 +132,6 @@ export class Features {
export class Flights {
public static readonly SettingsV2 = "settingsv2";
public static readonly MongoIndexEditor = "mongoindexeditor";
public static readonly MongoIndexing = "mongoindexing";
}
export class AfecFeatures {

View File

@@ -23,10 +23,10 @@ export class Splitter {
public splitterId: string;
public leftSideId: string;
public splitter!: HTMLElement;
public leftSide!: HTMLElement;
public lastX!: number;
public lastWidth!: number;
public splitter: HTMLElement;
public leftSide: HTMLElement;
public lastX: number;
public lastWidth: number;
private isCollapsed: ko.Observable<boolean>;
private bounds: SplitterBounds;
@@ -42,10 +42,9 @@ export class Splitter {
}
public initialize() {
if (document.getElementById(this.splitterId) !== null && document.getElementById(this.leftSideId) != null) {
this.splitter = <HTMLElement>document.getElementById(this.splitterId);
this.leftSide = <HTMLElement>document.getElementById(this.leftSideId);
}
this.splitter = document.getElementById(this.splitterId);
this.leftSide = document.getElementById(this.leftSideId);
const isVerticalSplitter: boolean = this.direction === SplitterDirection.Vertical;
const splitterOptions: JQueryUI.ResizableOptions = {
animate: true,

View File

@@ -138,8 +138,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
// Mongo container with system partition key still treat as "Fixed"
this.isFixedContainer =
this.container.isPreferredApiMongoDB() &&
(!this.collection.partitionKey || this.collection.partitionKey.systemKey);
!this.collection.partitionKey ||
(this.container.isPreferredApiMongoDB() && this.collection.partitionKey.systemKey);
this.state = {
throughput: undefined,
@@ -801,7 +801,12 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onMaxAutoPilotThroughputChange = (newThroughput: number): void =>
this.setState({ autoPilotThroughput: newThroughput });
private onThroughputChange = (newThroughput: number): void => this.setState({ throughput: newThroughput });
private onThroughputChange = (newThroughput: number): void => {
if (newThroughput < 400) {
return alert("The value should not small than 400");
}
this.setState({ throughput: newThroughput });
};
private onAutoPilotSelected = (isAutoPilotSelected: boolean): void =>
this.setState({ isAutoPilotSelected: isAutoPilotSelected });

View File

@@ -66,7 +66,7 @@ export interface PriceBreakdown {
currencySign: string;
}
export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 14 } };
export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 12 } };
export const noLeftPaddingCheckBoxStyle: ICheckboxStyles = {
label: {
@@ -166,10 +166,7 @@ export const separatorStyles: Partial<ISeparatorStyles> = {
]
};
export const messageBarStyles: Partial<IMessageBarStyles> = {
root: { marginTop: "5px", backgroundColor: "white" },
text: { fontSize: 14 }
};
export const messageBarStyles: Partial<IMessageBarStyles> = { root: { marginTop: "5px" } };
export const throughputUnit = "RU/s";

View File

@@ -8,7 +8,7 @@ exports[`IndexingPolicyRefreshComponent renders 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}

View File

@@ -16,7 +16,7 @@ import {
} from "../SettingsRenderUtils";
import { hasDatabaseSharedThroughput } from "../SettingsUtils";
import * as AutoPilotUtils from "../../../../Utils/AutoPilotUtils";
import { Link, Text, TextField, Stack, Label, MessageBar, MessageBarType } from "office-ui-fabric-react";
import { Text, TextField, Stack, Label, MessageBar, MessageBarType } from "office-ui-fabric-react";
import { configContext, Platform } from "../../../../ConfigContext";
export interface ScaleComponentProps {
@@ -176,7 +176,6 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
label={this.getThroughputTitle()}
isEmulator={this.isEmulator}
isFixed={this.props.isFixedContainer}
isFreeTierAccount={this.isFreeTierAccount()}
isAutoPilotSelected={this.props.isAutoPilotSelected}
onAutoPilotSelected={this.props.onAutoPilotSelected}
wasAutopilotOriginallySet={this.props.wasAutopilotOriginallySet}
@@ -191,37 +190,9 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
/>
);
private isFreeTierAccount(): boolean {
const databaseAccount = this.props.container?.databaseAccount();
return databaseAccount?.properties?.enableFreeTier;
}
private getFreeTierInfoMessage(): JSX.Element {
return (
<Text>
With free tier, you will get the first 400 RU/s and 5 GB of storage in this account for free. To keep your
account free, keep the total RU/s across all resources in the account to 400 RU/s.
<Link
href="https://docs.microsoft.com/en-us/azure/cosmos-db/understand-your-bill#billing-examples-with-free-tier-accounts"
target="_blank"
>
Learn more.
</Link>
</Text>
);
}
public render(): JSX.Element {
return (
<Stack {...subComponentStackProps}>
{this.isFreeTierAccount() && (
<MessageBar
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
styles={{ text: { fontSize: 14 } }}
>
{this.getFreeTierInfoMessage()}
</MessageBar>
)}
{this.getInitialNotificationElement() && (
<MessageBar messageBarType={MessageBarType.warning}>{this.getInitialNotificationElement()}</MessageBar>
)}

View File

@@ -13,7 +13,16 @@ import {
} from "../SettingsUtils";
import Explorer from "../../../Explorer";
import { Int32 } from "../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
import { Label, Text, TextField, Stack, IChoiceGroupOption, ChoiceGroup, MessageBar } from "office-ui-fabric-react";
import {
Label,
Text,
TextField,
Stack,
IChoiceGroupOption,
ChoiceGroup,
MessageBar,
MessageBarType
} from "office-ui-fabric-react";
import {
getTextFieldStyles,
changeFeedPolicyToolTip,
@@ -181,10 +190,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
styles={getChoiceGroupStyles(this.props.timeToLive, this.props.timeToLiveBaseline)}
/>
{isDirty(this.props.timeToLive, this.props.timeToLiveBaseline) && this.props.timeToLive === TtlType.On && (
<MessageBar
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
styles={messageBarStyles}
>
<MessageBar messageBarType={MessageBarType.warning} styles={messageBarStyles}>
{ttlWarning}
</MessageBar>
)}

View File

@@ -26,7 +26,6 @@ describe("ThroughputInputAutoPilotV3Component", () => {
spendAckVisible: false,
showAsMandatory: true,
isFixed: false,
isFreeTierAccount: false,
label: "label",
infoBubbleText: "infoBubbleText",
canExceedMaximumValue: true,

View File

@@ -28,6 +28,7 @@ import {
Label,
Link,
MessageBar,
MessageBarType,
FontIcon,
IColumn
} from "office-ui-fabric-react";
@@ -57,7 +58,6 @@ export interface ThroughputInputAutoPilotV3Props {
spendAckVisible?: boolean;
showAsMandatory?: boolean;
isFixed: boolean;
isFreeTierAccount: boolean;
isEmulator: boolean;
label: string;
infoBubbleText?: string;
@@ -76,7 +76,6 @@ export interface ThroughputInputAutoPilotV3Props {
interface ThroughputInputAutoPilotV3State {
spendAckChecked: boolean;
exceedFreeTierThroughput: boolean;
}
export class ThroughputInputAutoPilotV3Component extends React.Component<
@@ -150,9 +149,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
public constructor(props: ThroughputInputAutoPilotV3Props) {
super(props);
this.state = {
spendAckChecked: this.props.spendAckChecked,
exceedFreeTierThroughput:
this.props.isFreeTierAccount && !this.props.isAutoPilotSelected && this.props.throughput > 400
spendAckChecked: this.props.spendAckChecked
};
this.step = this.props.step ?? ThroughputInputAutoPilotV3Component.defaultStep;
@@ -427,7 +424,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
newValue?: string
): void => {
const newThroughput = getSanitizedInputValue(newValue);
const newThroughput = getSanitizedInputValue(newValue, this.autoPilotInputMaxValue);
this.props.onMaxAutoPilotThroughputChange(newThroughput);
};
@@ -435,11 +432,10 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
newValue?: string
): void => {
const newThroughput = getSanitizedInputValue(newValue);
const newThroughput = getSanitizedInputValue(newValue, this.throughputInputMaxValue);
if (this.overrideWithAutoPilotSettings()) {
this.props.onMaxAutoPilotThroughputChange(newThroughput);
} else {
this.setState({ exceedFreeTierThroughput: this.props.isFreeTierAccount && newThroughput > 400 });
this.props.onThroughputChange(newThroughput);
}
};
@@ -483,10 +479,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
/>
</Label>
{this.overrideWithProvisionedThroughputSettings() && (
<MessageBar
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
styles={messageBarStyles}
>
<MessageBar messageBarType={MessageBarType.warning} styles={messageBarStyles}>
{manualToAutoscaleDisclaimerElement}
</MessageBar>
)}
@@ -563,21 +556,8 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
}
onChange={this.onThroughputChange}
/>
{this.state.exceedFreeTierThroughput && (
<MessageBar
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
styles={messageBarStyles}
>
{
"Billing will apply if you provision more than 400 RU/s of manual throughput, or if the resource scales beyond 400 RU/s with autoscale."
}
</MessageBar>
)}
{this.props.getThroughputWarningMessage() && (
<MessageBar
messageBarIconProps={{ iconName: "InfoSolid", className: "messageBarInfoIcon" }}
styles={messageBarStyles}
>
<MessageBar messageBarType={MessageBarType.warning} styles={messageBarStyles}>
{this.props.getThroughputWarningMessage()}
</MessageBar>
)}
@@ -603,15 +583,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
warningMessage = saveThroughputWarningMessage;
}
return (
<>
{warningMessage && (
<MessageBar messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}>
{warningMessage}
</MessageBar>
)}
</>
);
return <>{warningMessage && <MessageBar messageBarType={MessageBarType.warning}>{warningMessage}</MessageBar>}</>;
};
public render(): JSX.Element {

View File

@@ -9,18 +9,13 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
}
>
<StyledMessageBarBase
messageBarIconProps={
Object {
"className": "messageBarWarningIcon",
"iconName": "WarningSolid",
}
}
messageBarType={5}
>
<Text
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -39,7 +34,7 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -50,21 +45,12 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
/>
</StyledLabelBase>
<StyledMessageBarBase
messageBarIconProps={
Object {
"className": "messageBarInfoIcon",
"iconName": "InfoSolid",
}
}
messageBarType={5}
styles={
Object {
"root": Object {
"backgroundColor": "white",
"marginTop": "5px",
},
"text": Object {
"fontSize": 14,
},
}
}
>
@@ -73,7 +59,7 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -185,7 +171,7 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -458,7 +444,7 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}

View File

@@ -16,7 +16,7 @@ exports[`ScaleComponent renders with correct initial notification 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}

View File

@@ -136,7 +136,7 @@ exports[`SubSettingsComponent analyticalTimeToLive hidden 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -412,7 +412,7 @@ exports[`SubSettingsComponent analyticalTimeToLiveSeconds hidden 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -952,7 +952,7 @@ exports[`SubSettingsComponent renders 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -1228,7 +1228,7 @@ exports[`SubSettingsComponent timeToLiveSeconds hidden 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}

View File

@@ -101,13 +101,13 @@ export const parseConflictResolutionProcedure = (procedureFromBackEnd: string):
return procedureFromBackEnd;
};
export const getSanitizedInputValue = (newValueString: string, max?: number): number => {
export const getSanitizedInputValue = (newValueString: string, max: number): number => {
const newValue = parseInt(newValueString);
if (isNaN(newValue)) {
return zeroValue;
}
// make sure new value does not exceed the maximum throughput
return max ? Math.min(newValue, max) : newValue;
return Math.min(newValue, max);
};
export const isDirty = (current: isDirtyTypes, baseline: isDirtyTypes): boolean => {

View File

@@ -55,7 +55,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -105,7 +104,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -593,7 +591,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -668,7 +665,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -954,7 +950,6 @@ exports[`SettingsComponent renders 1`] = `
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isLinkInjectionEnabled": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
@@ -1180,9 +1175,11 @@ exports[`SettingsComponent renders 1`] = `
},
"direction": "vertical",
"isCollapsed": [Function],
"leftSide": null,
"leftSideId": "resourcetree",
"onResizeStart": [Function],
"onResizeStop": [Function],
"splitter": null,
"splitterId": "h_splitter1",
},
"stringInputPane": StringInputPane {
@@ -1329,7 +1326,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -1379,7 +1375,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -1867,7 +1862,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -1942,7 +1936,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -2228,7 +2221,6 @@ exports[`SettingsComponent renders 1`] = `
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isLinkInjectionEnabled": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
@@ -2454,9 +2446,11 @@ exports[`SettingsComponent renders 1`] = `
},
"direction": "vertical",
"isCollapsed": [Function],
"leftSide": null,
"leftSideId": "resourcetree",
"onResizeStart": [Function],
"onResizeStop": [Function],
"splitter": null,
"splitterId": "h_splitter1",
},
"stringInputPane": StringInputPane {
@@ -2616,7 +2610,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -2666,7 +2659,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -3154,7 +3146,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -3229,7 +3220,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -3515,7 +3505,6 @@ exports[`SettingsComponent renders 1`] = `
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isLinkInjectionEnabled": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
@@ -3741,9 +3730,11 @@ exports[`SettingsComponent renders 1`] = `
},
"direction": "vertical",
"isCollapsed": [Function],
"leftSide": null,
"leftSideId": "resourcetree",
"onResizeStart": [Function],
"onResizeStop": [Function],
"splitter": null,
"splitterId": "h_splitter1",
},
"stringInputPane": StringInputPane {
@@ -3890,7 +3881,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -3940,7 +3930,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -4428,7 +4417,6 @@ exports[`SettingsComponent renders 1`] = `
"formErrors": [Function],
"formErrorsDetails": [Function],
"formWarnings": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "addcollectionpane",
"isAnalyticalStorageOn": [Function],
"isAutoPilotSelected": [Function],
@@ -4503,7 +4491,6 @@ exports[`SettingsComponent renders 1`] = `
"firstFieldHasFocus": [Function],
"formErrors": [Function],
"formErrorsDetails": [Function],
"freeTierExceedThroughputTooltip": [Function],
"id": "adddatabasepane",
"isAutoPilotSelected": [Function],
"isExecuting": [Function],
@@ -4789,7 +4776,6 @@ exports[`SettingsComponent renders 1`] = `
"isHostedDataExplorerEnabled": [Function],
"isLeftPaneExpanded": [Function],
"isLinkInjectionEnabled": [Function],
"isMongoIndexingEnabled": [Function],
"isNotebookEnabled": [Function],
"isNotebooksEnabledForAccount": [Function],
"isNotificationConsoleExpanded": [Function],
@@ -5015,9 +5001,11 @@ exports[`SettingsComponent renders 1`] = `
},
"direction": "vertical",
"isCollapsed": [Function],
"leftSide": null,
"leftSideId": "resourcetree",
"onResizeStart": [Function],
"onResizeStop": [Function],
"splitter": null,
"splitterId": "h_splitter1",
},
"stringInputPane": StringInputPane {

View File

@@ -159,7 +159,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -176,7 +176,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -195,7 +195,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -207,7 +207,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -219,7 +219,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -230,7 +230,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -249,7 +249,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -268,7 +268,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -286,7 +286,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -299,7 +299,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -310,7 +310,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -329,7 +329,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -371,7 +371,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -386,7 +386,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}
@@ -402,7 +402,7 @@ exports[`SettingsUtils functions render 1`] = `
styles={
Object {
"root": Object {
"fontSize": 14,
"fontSize": 12,
},
}
}

View File

@@ -129,8 +129,6 @@ export interface ThroughputInputParams {
showAutoPilot?: ko.Observable<boolean>;
overrideWithAutoPilotSettings: ko.Observable<boolean>;
overrideWithProvisionedThroughputSettings: ko.Observable<boolean>;
freeTierExceedThroughputTooltip?: ko.Observable<string>;
freeTierExceedThroughputWarning?: ko.Observable<string>;
}
export class ThroughputInputViewModel extends WaitsForTemplateViewModel {
@@ -167,10 +165,6 @@ export class ThroughputInputViewModel extends WaitsForTemplateViewModel {
public overrideWithProvisionedThroughputSettings: ko.Observable<boolean>;
public isManualThroughputInputFieldRequired: ko.Computed<boolean>;
public isAutoscaleThroughputInputFieldRequired: ko.Computed<boolean>;
public freeTierExceedThroughputTooltip: ko.Observable<string>;
public freeTierExceedThroughputWarning: ko.Observable<string>;
public showFreeTierExceedThroughputTooltip: ko.Computed<boolean>;
public showFreeTierExceedThroughputWarning: ko.Computed<boolean>;
public constructor(options: ThroughputInputParams) {
super();
@@ -225,16 +219,6 @@ export class ThroughputInputViewModel extends WaitsForTemplateViewModel {
this.isAutoscaleThroughputInputFieldRequired = ko.pureComputed(
() => this.isEnabled() && this.isAutoPilotSelected()
);
this.freeTierExceedThroughputTooltip = options.freeTierExceedThroughputTooltip || ko.observable<string>();
this.freeTierExceedThroughputWarning = options.freeTierExceedThroughputWarning || ko.observable<string>();
this.showFreeTierExceedThroughputTooltip = ko.pureComputed<boolean>(
() => !!this.freeTierExceedThroughputTooltip() && this.value() > 400
);
this.showFreeTierExceedThroughputWarning = ko.pureComputed<boolean>(
() => !!this.freeTierExceedThroughputWarning() && this.value() > 400
);
}
public decreaseThroughput() {
@@ -283,6 +267,12 @@ export class ThroughputInputViewModel extends WaitsForTemplateViewModel {
return true;
};
public onThroughputCheck = (event: any) => {
if (event.value() < 400) {
window.alert("The value should not small than 400");
}
};
private _getSanitizedValue(): number {
let throughput = this.value();

View File

@@ -132,14 +132,6 @@
<a target="_blank" href="https://cosmos.azure.com/capacitycalculator/">capacity calculator</a></span
>
</p>
<div class="inputTooltip">
<span
data-bind="text: freeTierExceedThroughputTooltip, visible: showFreeTierExceedThroughputTooltip"
class="inputTooltipText"
></span>
</div>
<div data-bind="setTemplateReady: true">
<input
data-bind="
@@ -158,15 +150,13 @@
'aria-label': ariaLabel,
disabled: overrideWithAutoPilotSettings(),
required: isManualThroughputInputFieldRequired()
},
event:{
change: onThroughputCheck
}"
/>
</div>
<div class="freeTierInlineWarning" data-bind="visible: showFreeTierExceedThroughputWarning">
<span class="freeTierWarningIcon"><img src="/warning.svg" alt="Warning"/></span>
<span class="freeTierWarningMessage" data-bind="text: freeTierExceedThroughputWarning"></span>
</div>
<p data-bind="visible: costsVisible">
<span data-bind="html: requestUnitsUsageCost"></span>
</p>

View File

@@ -207,7 +207,6 @@ export default class Explorer {
public isCopyNotebookPaneEnabled: ko.Observable<boolean>;
public isHostedDataExplorerEnabled: ko.Computed<boolean>;
public isRightPanelV2Enabled: ko.Computed<boolean>;
public isMongoIndexingEnabled: ko.Observable<boolean>;
public canExceedMaximumValue: ko.Computed<boolean>;
public shouldShowShareDialogContents: ko.Observable<boolean>;
@@ -403,7 +402,6 @@ export default class Explorer {
this.isFeatureEnabled(Constants.Features.enableLinkInjection)
);
this.isGitHubPaneEnabled = ko.observable<boolean>(false);
this.isMongoIndexingEnabled = ko.observable<boolean>(false);
this.isPublishNotebookPaneEnabled = ko.observable<boolean>(false);
this.isCopyNotebookPaneEnabled = ko.observable<boolean>(false);
@@ -1898,9 +1896,6 @@ export default class Explorer {
if (!flights) {
return;
}
if (flights.indexOf(Constants.Flights.MongoIndexing) !== -1) {
this.isMongoIndexingEnabled(true);
}
}
public findSelectedCollection(): ViewModels.Collection {
@@ -3019,25 +3014,4 @@ export default class Explorer {
})
);
}
public isFirstResourceCreated(): boolean {
const databases: ViewModels.Database[] = this.databases();
if (!databases || databases.length === 0) {
return false;
}
return databases.some(database => {
// user has created at least one collection
if (database.collections()?.length > 0) {
return true;
}
// user has created a database with shared throughput
if (database.offer()) {
return true;
}
// use has created an empty database without shared throughput
return false;
});
}
}

View File

@@ -152,8 +152,7 @@
maxAutoPilotThroughputSet: sharedAutoPilotThroughput,
autoPilotUsageCost: autoPilotUsageCost,
canExceedMaximumValue: canExceedMaximumValue,
showAutoPilot: !isFreeTierAccount(),
freeTierExceedThroughputTooltip: freeTierExceedThroughputTooltip
showAutoPilot: !isFreeTierAccount()
}">
</throughput-input-autopilot-v3>
</div>
@@ -334,8 +333,7 @@
maxAutoPilotThroughputSet: autoPilotThroughput,
autoPilotUsageCost: autoPilotUsageCost,
canExceedMaximumValue: canExceedMaximumValue,
showAutoPilot: !isFixedStorageSelected(),
freeTierExceedThroughputTooltip: freeTierExceedThroughputTooltip
showAutoPilot: !isFixedStorageSelected()
}">
</throughput-input-autopilot-v3>
</div>

View File

@@ -74,7 +74,7 @@ describe("Add Collection Pane", () => {
explorer.databaseAccount(mockFreeTierDatabaseAccount);
const addCollectionPane = explorer.addCollectionPane as AddCollectionPane;
expect(addCollectionPane.isFreeTierAccount()).toBe(true);
expect(addCollectionPane.upsellMessage()).toContain("With free tier");
expect(addCollectionPane.upsellMessage()).toContain("With free tier discount");
expect(addCollectionPane.upsellAnchorUrl()).toBe(Constants.Urls.freeTierInformation);
expect(addCollectionPane.upsellAnchorText()).toBe("Learn more");
});

View File

@@ -89,10 +89,9 @@ export default class AddCollectionPane extends ContextualPaneBase {
public isSynapseLinkUpdating: ko.Computed<boolean>;
public canExceedMaximumValue: ko.PureComputed<boolean>;
public ruToolTipText: ko.Computed<string>;
public freeTierExceedThroughputTooltip: ko.Computed<string>;
public canConfigureThroughput: ko.PureComputed<boolean>;
public showUpsellMessage: ko.PureComputed<boolean>;
public shouldCreateMongoWildcardIndex: ko.Computed<boolean>;
public shouldCreateMongoWildcardIndex: ko.Observable<boolean>;
private _isSynapseLinkEnabled: ko.Computed<boolean>;
@@ -100,6 +99,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
super(options);
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText());
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
this.showUpsellMessage = ko.pureComputed(() => !this.container.isServerlessEnabled());
this.formWarnings = ko.observable<string>();
this.collectionId = ko.observable<string>();
this.databaseId = ko.observable<string>();
@@ -481,20 +481,8 @@ export default class AddCollectionPane extends ContextualPaneBase {
this.resetData();
});
this.freeTierExceedThroughputTooltip = ko.pureComputed<string>(() =>
this.isFreeTierAccount() && !this.container.isFirstResourceCreated()
? "The first 400 RU/s in this account are free. Billing will apply to any throughput beyond 400 RU/s."
: ""
);
this.upsellMessage = ko.pureComputed<string>(() => {
return PricingUtils.getUpsellMessage(
this.container.serverId(),
this.isFreeTierAccount(),
this.container.isFirstResourceCreated(),
this.container.defaultExperience(),
true
);
return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount());
});
this.upsellMessageAriaLabel = ko.pureComputed<string>(() => {
@@ -546,23 +534,6 @@ export default class AddCollectionPane extends ContextualPaneBase {
return isFreeTierAccount;
});
this.showUpsellMessage = ko.pureComputed(() => {
if (this.container.isServerlessEnabled()) {
return false;
}
if (
this.isFreeTierAccount() &&
!this.databaseCreateNew() &&
this.databaseHasSharedOffer() &&
!this.collectionWithThroughputInShared()
) {
return false;
}
return true;
});
this.showIndexingOptionsForSharedThroughput = ko.computed<boolean>(() => {
const newDatabaseWithSharedOffer = this.databaseCreateNew() && this.databaseCreateNewShared();
const existingDatabaseWithSharedOffer = !this.databaseCreateNew() && this.databaseHasSharedOffer();
@@ -654,9 +625,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
});
});
this.shouldCreateMongoWildcardIndex = ko.computed(function() {
return this.container.isMongoIndexingEnabled();
}, this);
this.shouldCreateMongoWildcardIndex = ko.observable(false);
}
public getSharedThroughputDefault(): boolean {

View File

@@ -114,8 +114,7 @@
maxAutoPilotThroughputSet: maxAutoPilotThroughputSet,
autoPilotUsageCost: autoPilotUsageCost,
canExceedMaximumValue: canExceedMaximumValue,
showAutoPilot: !isFreeTierAccount(),
freeTierExceedThroughputTooltip: freeTierExceedThroughputTooltip
showAutoPilot: !isFreeTierAccount()
}">
</throughput-input-autopilot-v3>
<p data-bind="visible: canRequestSupport">

View File

@@ -77,7 +77,7 @@ describe("Add Database Pane", () => {
explorer.databaseAccount(mockFreeTierDatabaseAccount);
const addDatabasePane = explorer.addDatabasePane as AddDatabasePane;
expect(addDatabasePane.isFreeTierAccount()).toBe(true);
expect(addDatabasePane.upsellMessage()).toContain("With free tier");
expect(addDatabasePane.upsellMessage()).toContain("With free tier discount");
expect(addDatabasePane.upsellAnchorUrl()).toBe(Constants.Urls.freeTierInformation);
expect(addDatabasePane.upsellAnchorText()).toBe("Learn more");
});

View File

@@ -44,7 +44,6 @@ export default class AddDatabasePane extends ContextualPaneBase {
public autoPilotUsageCost: ko.Computed<string>;
public canExceedMaximumValue: ko.PureComputed<boolean>;
public ruToolTipText: ko.Computed<string>;
public freeTierExceedThroughputTooltip: ko.Computed<string>;
public isFreeTierAccount: ko.Computed<boolean>;
public canConfigureThroughput: ko.PureComputed<boolean>;
public showUpsellMessage: ko.PureComputed<boolean>;
@@ -55,6 +54,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
this.databaseId = ko.observable<string>();
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText());
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
this.showUpsellMessage = ko.pureComputed(() => !this.container.isServerlessEnabled());
this.canExceedMaximumValue = ko.pureComputed(() => this.container.canExceedMaximumValue());
@@ -182,18 +182,6 @@ export default class AddDatabasePane extends ContextualPaneBase {
return isFreeTierAccount;
});
this.showUpsellMessage = ko.pureComputed(() => {
if (this.container.isServerlessEnabled()) {
return false;
}
if (this.isFreeTierAccount()) {
return this.databaseCreateNewShared();
}
return true;
});
this.maxThroughputRUText = ko.pureComputed(() => {
return this.maxThroughputRU().toLocaleString();
});
@@ -231,20 +219,8 @@ export default class AddDatabasePane extends ContextualPaneBase {
this.resetData();
});
this.freeTierExceedThroughputTooltip = ko.pureComputed<string>(() =>
this.isFreeTierAccount() && !this.container.isFirstResourceCreated()
? "The first 400 RU/s in this account are free. Billing will apply to any throughput beyond 400 RU/s."
: ""
);
this.upsellMessage = ko.pureComputed<string>(() => {
return PricingUtils.getUpsellMessage(
this.container.serverId(),
this.isFreeTierAccount(),
this.container.isFirstResourceCreated(),
this.container.defaultExperience(),
false
);
return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount());
});
this.upsellMessageAriaLabel = ko.pureComputed<string>(() => {

View File

@@ -23,19 +23,6 @@
<div class="scaleDivison" aria-label="Scale" aria-controls="scaleRegion">
<span class="scaleSettingTitle">Scale</span>
</div>
<div class="freeTierInfoBanner" data-bind="visible: isFreeTierAccount">
<span class="freeTierInfoIcon"><img src="/info_color.svg" alt="Info"/></span>
<span class="freeTierInfoMessage"
>With free tier, you'll get the first 400 RU/s and 5 GB of storage in this account for free. To keep your
account free, keep the total RU/s across all resources in the account to 400 RU/s.
<a
href="https://docs.microsoft.com/en-us/azure/cosmos-db/understand-your-bill#billing-examples-with-free-tier-accounts"
target="_blank"
>
Learn more.</a
>
</span>
</div>
<div class="ssTextAllignment" id="scaleRegion">
<throughput-input-autopilot-v3
params="{
@@ -59,8 +46,7 @@
autoPilotUsageCost: autoPilotUsageCost,
canExceedMaximumValue: canExceedMaximumValue,
overrideWithAutoPilotSettings: overrideWithAutoPilotSettings,
overrideWithProvisionedThroughputSettings: overrideWithProvisionedThroughputSettings,
freeTierExceedThroughputWarning: freeTierExceedThroughputWarning
overrideWithProvisionedThroughputSettings: overrideWithProvisionedThroughputSettings
}"
>
</throughput-input-autopilot-v3>

View File

@@ -57,7 +57,6 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
public canThroughputExceedMaximumValue: ko.Computed<boolean>;
public costsVisible: ko.Computed<boolean>;
public displayedError: ko.Observable<string>;
public isFreeTierAccount: ko.Computed<boolean>;
public isTemplateReady: ko.Observable<boolean>;
public minRUAnotationVisible: ko.Computed<boolean>;
public minRUs: ko.Observable<number>;
@@ -83,7 +82,6 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
public throughputAutoPilotRadioId: string;
public throughputProvisionedRadioId: string;
public throughputModeRadioName: string;
public freeTierExceedThroughputWarning: ko.Computed<string>;
private _hasProvisioningTypeChanged: ko.Computed<boolean>;
private _wasAutopilotOriginallySet: ko.Observable<boolean>;
@@ -361,17 +359,6 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
this.isTemplateReady = ko.observable<boolean>(false);
this.isFreeTierAccount = ko.computed<boolean>(() => {
const databaseAccount = this.container?.databaseAccount();
return databaseAccount?.properties?.enableFreeTier;
});
this.freeTierExceedThroughputWarning = ko.computed<string>(() =>
this.isFreeTierAccount()
? "Billing will apply if you provision more than 400 RU/s of manual throughput, or if the resource scales beyond 400 RU/s with autoscale."
: ""
);
this._buildCommandBarOptions();
}

View File

@@ -324,6 +324,21 @@ export default class QueryTab extends TabsBase implements ViewModels.WaitsForTem
queryResults.itemCount > 0 ? `${queryResults.firstItemIndex} - ${queryResults.lastItemIndex}` : `0 - 0`;
this.showingDocumentsDisplayText(resultsDisplay);
this.requestChargeDisplayText(`${queryResults.requestCharge} RUs`);
if (!this.queryResults() && !results) {
const errorMessage: string = JSON.stringify({
error: `Returned no results after query execution`,
accountName: this.collection && this.collection.container.databaseAccount(),
databaseName: this.collection && this.collection.databaseId,
collectionName: this.collection && this.collection.id(),
sqlQuery: this.sqlStatementToExecute(),
hasMoreResults: resultsMetadata.hasMoreResults,
itemCount: resultsMetadata.itemCount,
responseHeaders: queryResults && queryResults.headers
});
Logger.logError(errorMessage, "QueryTab");
}
this.queryResults(results);
TelemetryProcessor.traceSuccess(

View File

@@ -2,42 +2,33 @@ import * as Constants from "../../../Common/Constants";
import * as DataModels from "../../../Contracts/DataModels";
export class ConnectionStringParser {
public static parseConnectionString(connectionString: string): DataModels.AccessInputMetadata | undefined {
public static parseConnectionString(connectionString: string): DataModels.AccessInputMetadata {
if (!!connectionString) {
try {
const accessInput: DataModels.AccessInputMetadata = {} as DataModels.AccessInputMetadata;
const connectionStringParts = connectionString.split(";");
connectionStringParts.forEach((connectionStringPart: string) => {
const sqlMatchResult = connectionStringPart.match(Constants.EndpointsRegex.sql);
const mongoMatchResult = connectionStringPart.match(Constants.EndpointsRegex.mongo);
const mongoComputeMatchResult = connectionStringPart.match(Constants.EndpointsRegex.mongoCompute);
const tableMatchResult = connectionStringPart.match(Constants.EndpointsRegex.table);
if (sqlMatchResult && sqlMatchResult.length > 1) {
accessInput.accountName = sqlMatchResult[1];
if (RegExp(Constants.EndpointsRegex.sql).test(connectionStringPart)) {
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.sql)[1];
accessInput.apiKind = DataModels.ApiKind.SQL;
} else if (mongoMatchResult && mongoMatchResult.length > 2) {
accessInput.accountName = mongoMatchResult[2];
} else if (RegExp(Constants.EndpointsRegex.mongo).test(connectionStringPart)) {
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongo);
accessInput.accountName = matches && matches.length > 1 && matches[2];
accessInput.apiKind = DataModels.ApiKind.MongoDB;
} else if (mongoComputeMatchResult && mongoComputeMatchResult.length > 2) {
accessInput.accountName = mongoComputeMatchResult[2];
} else if (RegExp(Constants.EndpointsRegex.mongoCompute).test(connectionStringPart)) {
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongoCompute);
accessInput.accountName = matches && matches.length > 1 && matches[2];
accessInput.apiKind = DataModels.ApiKind.MongoDBCompute;
} else if (
Constants.EndpointsRegex.cassandra &&
Constants.EndpointsRegex.cassandra.some(regex => RegExp(regex).test(connectionStringPart))
) {
} else if (Constants.EndpointsRegex.cassandra.some(regex => RegExp(regex).test(connectionStringPart))) {
Constants.EndpointsRegex.cassandra.forEach(regex => {
if (RegExp(regex).test(connectionStringPart)) {
const connectionMatch = connectionStringPart.match(regex);
if (connectionMatch && connectionMatch.length > 1) {
accessInput.accountName = connectionMatch[1];
accessInput.apiKind = DataModels.ApiKind.Cassandra;
}
accessInput.accountName = connectionStringPart.match(regex)[1];
accessInput.apiKind = DataModels.ApiKind.Cassandra;
}
});
} else if (tableMatchResult && tableMatchResult.length > 1) {
accessInput.accountName = tableMatchResult[1];
} else if (RegExp(Constants.EndpointsRegex.table).test(connectionStringPart)) {
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.table)[1];
accessInput.apiKind = DataModels.ApiKind.Table;
} else if (connectionStringPart.indexOf("ApiKind=Gremlin") >= 0) {
accessInput.apiKind = DataModels.ApiKind.Graph;

View File

@@ -4,7 +4,7 @@ import * as DataModels from "../Contracts/DataModels";
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
export class DefaultExperienceUtility {
public static getDefaultExperienceFromDatabaseAccount(databaseAccount: DataModels.DatabaseAccount): string | null {
public static getDefaultExperienceFromDatabaseAccount(databaseAccount: DataModels.DatabaseAccount): string {
if (!databaseAccount) {
return null;
}
@@ -81,9 +81,11 @@ export class DefaultExperienceUtility {
private static _getDefaultExperience(kind: string, capabilities: DataModels.Capability[]): string {
const defaultDefaultExperience: string = Constants.DefaultAccountExperience.DocumentDB;
const defaultExperienceFromKind: string = DefaultExperienceUtility._getDefaultExperienceFromAccountKind(kind) || "";
const defaultExperienceFromCapabilities: string =
DefaultExperienceUtility._getDefaultExperienceFromAccountCapabilities(capabilities) || "";
const defaultExperienceFromKind: string = DefaultExperienceUtility._getDefaultExperienceFromAccountKind(kind);
const defaultExperienceFromCapabilities: string = DefaultExperienceUtility._getDefaultExperienceFromAccountCapabilities(
capabilities
);
if (!!defaultExperienceFromKind) {
return defaultExperienceFromKind;
}
@@ -95,7 +97,7 @@ export class DefaultExperienceUtility {
return defaultDefaultExperience;
}
private static _getDefaultExperienceFromAccountKind(kind: string): string | null {
private static _getDefaultExperienceFromAccountKind(kind: string): string {
if (!kind) {
return null;
}
@@ -111,7 +113,7 @@ export class DefaultExperienceUtility {
return null;
}
private static _getDefaultExperienceFromAccountCapabilities(capabilities: DataModels.Capability[]): string | null {
private static _getDefaultExperienceFromAccountCapabilities(capabilities: DataModels.Capability[]): string {
if (!capabilities) {
return null;
}

View File

@@ -1,6 +1,5 @@
import * as AutoPilotUtils from "../Utils/AutoPilotUtils";
import * as Constants from "../Shared/Constants";
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
interface ComputeRUUsagePriceHourlyArgs {
serverId: string;
@@ -257,19 +256,9 @@ export function getEstimatedSpendAcknowledgeString(
)} - ${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly cost for the throughput above.`;
}
export function getUpsellMessage(
serverId = "default",
isFreeTier = false,
isFirstResourceCreated = false,
defaultExperience: string,
isCollection: boolean
): string {
export function getUpsellMessage(serverId = "default", isFreeTier = false): string {
if (isFreeTier) {
const collectionName = getCollectionName(defaultExperience);
const resourceType = isCollection ? collectionName : "database";
return isFirstResourceCreated
? `The free tier discount of 400 RU/s has already been applied to a database or ${collectionName} in this account. Billing will apply to this ${resourceType} after it is created.`
: `With free tier, you'll get the first 400 RU/s and 5 GB of storage in this account for free. Billing will apply if you provision more than 400 RU/s of manual throughput, or if the ${resourceType} scales beyond 400 RU/s with autoscale.`;
return "With free tier discount, you'll get the first 400 RU/s and 5 GB of storage in this account for free. Charges will apply if your resource throughput exceeds 400 RU/s.";
} else {
let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice;
@@ -280,19 +269,3 @@ export function getUpsellMessage(
return `Start at ${getCurrencySign(serverId)}${price}/mo per database, multiple containers included`;
}
}
function getCollectionName(defaultExperience: string): string {
switch (defaultExperience) {
case DefaultAccountExperienceType.DocumentDB:
return "container";
case DefaultAccountExperienceType.MongoDB:
return "collection";
case DefaultAccountExperienceType.Table:
case DefaultAccountExperienceType.Cassandra:
return "table";
case DefaultAccountExperienceType.Graph:
return "graph";
default:
throw Error("unknown API type");
}
}

View File

@@ -12,8 +12,7 @@
"./src/Bindings/ReactBindingHandler.ts",
"./src/Common/ArrayHashMap.ts",
"./src/Common/Constants.ts",
"./src/Common/DeleteFeedback.ts",
"./src/Common/DocumentUtility.ts",
"./src/Common/DeleteFeedback.ts",
"./src/Common/EnvironmentUtility.ts",
"./src/Common/HashMap.ts",
"./src/Common/HeadersUtility.ts",
@@ -22,8 +21,7 @@
"./src/Common/MongoUtility.ts",
"./src/Common/ObjectCache.ts",
"./src/Common/ThemeUtility.ts",
"./src/Common/UrlUtility.ts",
"./src/Common/Splitter.ts",
"./src/Common/UrlUtility.ts",
"./src/ConfigContext.ts",
"./src/Contracts/ActionContracts.ts",
"./src/Contracts/DataModels.ts",
@@ -62,8 +60,6 @@
"./src/GitHub/GitHubConnector.ts",
"./src/Index.ts",
"./src/NotebookWorkspaceManager/NotebookWorkspaceResourceProviderMockClients.ts",
"./src/Platform/Hosted/Helpers/ConnectionStringParser.ts",
"./src/Platform/Hosted/HostedUtils.ts",
"./src/ReactDevTools.ts",
"./src/ResourceProvider/IResourceProviderClient.ts",
"./src/Shared/Constants.ts",