mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-27 12:51:41 +00:00
Compare commits
12 Commits
accessibil
...
accessibil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8144ed327 | ||
|
|
c1a5c6d9c6 | ||
|
|
60d666df1e | ||
|
|
ca9833e208 | ||
|
|
042ad24cc6 | ||
|
|
445427ecec | ||
|
|
6d19aaab43 | ||
|
|
7fbecfff1a | ||
|
|
712e0e0c1e | ||
|
|
6aa229462b | ||
|
|
990d86ffc6 | ||
|
|
9383609a22 |
@@ -45,8 +45,6 @@ export class ArmResourceTypes {
|
|||||||
|
|
||||||
export class BackendDefaults {
|
export class BackendDefaults {
|
||||||
public static partitionKeyKind = "Hash";
|
public static partitionKeyKind = "Hash";
|
||||||
public static partitionKeyMultiHash = "MultiHash";
|
|
||||||
public static maxNumMultiHashPartition = 2;
|
|
||||||
public static singlePartitionStorageInGb: string = "10";
|
public static singlePartitionStorageInGb: string = "10";
|
||||||
public static multiPartitionStorageInGb: string = "100";
|
public static multiPartitionStorageInGb: string = "100";
|
||||||
public static maxChangeFeedRetentionDuration: number = 10;
|
public static maxChangeFeedRetentionDuration: number = 10;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }:
|
|||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<TooltipHost content={children}>
|
<TooltipHost content={children}>
|
||||||
<Icon iconName="Info" ariaLabel={children} className="panelInfoIcon" tabIndex={0} />
|
<Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -397,7 +397,6 @@ export interface DataExplorerInputsFrame {
|
|||||||
defaultCollectionThroughput?: CollectionCreationDefaults;
|
defaultCollectionThroughput?: CollectionCreationDefaults;
|
||||||
isPostgresAccount?: boolean;
|
isPostgresAccount?: boolean;
|
||||||
isReplica?: 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
|
// 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;
|
connectionStringParams?: any;
|
||||||
flights?: readonly string[];
|
flights?: readonly string[];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { HoverCard, HoverCardType, Icon, Label, Link, Stack } from "@fluentui/react";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { Icon, Label, Stack, HoverCard, HoverCardType, Link } from "@fluentui/react";
|
||||||
import { CodeOfConductEndpoints } from "../../../../Common/Constants";
|
import { CodeOfConductEndpoints } from "../../../../Common/Constants";
|
||||||
import "./InfoComponent.less";
|
import "./InfoComponent.less";
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ export class InfoComponent extends React.Component<InfoComponentProps> {
|
|||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}>
|
<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" } }} />
|
<Icon className="infoIconMain" iconName="Help" styles={{ root: { verticalAlign: "middle" } }} />
|
||||||
<Label className="infoLabelMain">Help</Label>
|
<Label className="infoLabelMain">Help</Label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ exports[`InfoComponent renders 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="infoPanelMain"
|
className="infoPanelMain"
|
||||||
tabIndex={0}
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
className="infoIconMain"
|
className="infoIconMain"
|
||||||
|
|||||||
@@ -310,9 +310,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{userContext.apiType === "SQL" && this.isLargePartitionKeyEnabled() && (
|
{this.isLargePartitionKeyEnabled() && <Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>}
|
||||||
<Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ interface ThroughputInputAutoPilotV3State {
|
|||||||
spendAckChecked: boolean;
|
spendAckChecked: boolean;
|
||||||
exceedFreeTierThroughput: boolean;
|
exceedFreeTierThroughput: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ThroughputInputAutoPilotV3Component extends React.Component<
|
export class ThroughputInputAutoPilotV3Component extends React.Component<
|
||||||
ThroughputInputAutoPilotV3Props,
|
ThroughputInputAutoPilotV3Props,
|
||||||
ThroughputInputAutoPilotV3State
|
ThroughputInputAutoPilotV3State
|
||||||
@@ -623,10 +624,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{warningMessage && (
|
{warningMessage && (
|
||||||
<MessageBar
|
<MessageBar messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}>
|
||||||
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
|
|
||||||
role="alert"
|
|
||||||
>
|
|
||||||
{warningMessage}
|
{warningMessage}
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
|
|||||||
"iconName": "WarningSolid",
|
"iconName": "WarningSolid",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
role="alert"
|
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
styles={
|
styles={
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ describe("ThroughputInput Pane", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should switch mode properly", () => {
|
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(
|
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe(
|
||||||
"Container throughput (400 - unlimited RU/s)"
|
"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)");
|
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe("Container throughput (autoscale)");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -186,9 +186,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
|
|
||||||
<Stack horizontal verticalAlign="center">
|
<Stack horizontal verticalAlign="center">
|
||||||
<input
|
<input
|
||||||
id="Autoscale-input"
|
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
aria-label="Autoscale database throughput"
|
aria-label="Autoscale mode"
|
||||||
aria-required={true}
|
aria-required={true}
|
||||||
checked={isAutoscaleSelected}
|
checked={isAutoscaleSelected}
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -196,14 +195,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={(e) => handleOnChangeMode(e, "Autoscale")}
|
onChange={(e) => handleOnChangeMode(e, "Autoscale")}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="Autoscale-input" className="throughputInputRadioBtnLabel">
|
<span className="throughputInputRadioBtnLabel">Autoscale</span>
|
||||||
Autoscale
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<input
|
<input
|
||||||
id="Manual-input"
|
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
aria-label="Manual database throughput"
|
aria-label="Manual mode"
|
||||||
checked={!isAutoscaleSelected}
|
checked={!isAutoscaleSelected}
|
||||||
type="radio"
|
type="radio"
|
||||||
aria-required={true}
|
aria-required={true}
|
||||||
@@ -211,20 +207,14 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={(e) => handleOnChangeMode(e, "Manual")}
|
onChange={(e) => handleOnChangeMode(e, "Manual")}
|
||||||
/>
|
/>
|
||||||
<label className="throughputInputRadioBtnLabel" htmlFor="Manual-input">
|
<span className="throughputInputRadioBtnLabel">Manual</span>
|
||||||
Manual
|
|
||||||
</label>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
{isAutoscaleSelected && (
|
{isAutoscaleSelected && (
|
||||||
<Stack className="throughputInputSpacing">
|
<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{" "}
|
Estimate your required RU/s with{" "}
|
||||||
<Link
|
<Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/" aria-label="ruDescription">
|
||||||
target="_blank"
|
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
|
||||||
>
|
|
||||||
capacity calculator
|
capacity calculator
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -344,13 +344,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
>
|
>
|
||||||
<StyledIconBase
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<IconBase
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
styles={[Function]}
|
styles={[Function]}
|
||||||
@@ -630,7 +630,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i
|
<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"
|
className="panelInfoIcon root-57"
|
||||||
data-icon-name="Info"
|
data-icon-name="Info"
|
||||||
role="img"
|
role="img"
|
||||||
@@ -655,43 +655,39 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
className="ms-Stack css-58"
|
className="ms-Stack css-58"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
aria-label="Autoscale database throughput"
|
aria-label="Autoscale mode"
|
||||||
aria-required={true}
|
aria-required={true}
|
||||||
checked={true}
|
checked={true}
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
id="Autoscale-input"
|
|
||||||
key=".0:$.0"
|
key=".0:$.0"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
role="radio"
|
role="radio"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
type="radio"
|
type="radio"
|
||||||
/>
|
/>
|
||||||
<label
|
<span
|
||||||
className="throughputInputRadioBtnLabel"
|
className="throughputInputRadioBtnLabel"
|
||||||
htmlFor="Autoscale-input"
|
|
||||||
key=".0:$.1"
|
key=".0:$.1"
|
||||||
>
|
>
|
||||||
Autoscale
|
Autoscale
|
||||||
</label>
|
</span>
|
||||||
<input
|
<input
|
||||||
aria-label="Manual database throughput"
|
aria-label="Manual mode"
|
||||||
aria-required={true}
|
aria-required={true}
|
||||||
checked={false}
|
checked={false}
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
id="Manual-input"
|
|
||||||
key=".0:$.2"
|
key=".0:$.2"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
role="radio"
|
role="radio"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
type="radio"
|
type="radio"
|
||||||
/>
|
/>
|
||||||
<label
|
<span
|
||||||
className="throughputInputRadioBtnLabel"
|
className="throughputInputRadioBtnLabel"
|
||||||
htmlFor="Manual-input"
|
|
||||||
key=".0:$.3"
|
key=".0:$.3"
|
||||||
>
|
>
|
||||||
Manual
|
Manual
|
||||||
</label>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Stack
|
<Stack
|
||||||
@@ -701,23 +697,23 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
className="ms-Stack throughputInputSpacing css-59"
|
className="ms-Stack throughputInputSpacing css-59"
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
aria-label="ruDescription"
|
||||||
key=".0:$.0"
|
key=".0:$.0"
|
||||||
variant="small"
|
variant="small"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
aria-label="ruDescription"
|
||||||
className="css-54"
|
className="css-54"
|
||||||
>
|
>
|
||||||
Estimate your required RU/s with
|
Estimate your required RU/s with
|
||||||
|
|
||||||
<StyledLinkBase
|
<StyledLinkBase
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
aria-label="ruDescription"
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
href="https://cosmos.azure.com/capacitycalculator/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<LinkBase
|
<LinkBase
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
aria-label="ruDescription"
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
href="https://cosmos.azure.com/capacitycalculator/"
|
||||||
styles={[Function]}
|
styles={[Function]}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -996,7 +992,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-label="capacity calculator of azure cosmos db"
|
aria-label="ruDescription"
|
||||||
className="ms-Link root-60"
|
className="ms-Link root-60"
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
href="https://cosmos.azure.com/capacitycalculator/"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -1335,13 +1331,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
>
|
>
|
||||||
<StyledIconBase
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<IconBase
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
styles={[Function]}
|
styles={[Function]}
|
||||||
@@ -1621,7 +1617,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i
|
<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"
|
className="panelInfoIcon root-57"
|
||||||
data-icon-name="Info"
|
data-icon-name="Info"
|
||||||
role="img"
|
role="img"
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ describe("ContainerSampleGenerator", () => {
|
|||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Rejects with error that contains experience
|
||||||
expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience);
|
expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -89,10 +89,9 @@ export interface AddCollectionPanelState {
|
|||||||
enableIndexing: boolean;
|
enableIndexing: boolean;
|
||||||
isSharded: boolean;
|
isSharded: boolean;
|
||||||
partitionKey: string;
|
partitionKey: string;
|
||||||
subPartitionKeys: string[];
|
|
||||||
enableDedicatedThroughput: boolean;
|
enableDedicatedThroughput: boolean;
|
||||||
createMongoWildCardIndex: boolean;
|
createMongoWildCardIndex: boolean;
|
||||||
useHashV1: boolean;
|
useHashV2: boolean;
|
||||||
enableAnalyticalStore: boolean;
|
enableAnalyticalStore: boolean;
|
||||||
uniqueKeys: string[];
|
uniqueKeys: string[];
|
||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
@@ -122,11 +121,10 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
enableIndexing: true,
|
enableIndexing: true,
|
||||||
isSharded: userContext.apiType !== "Tables",
|
isSharded: userContext.apiType !== "Tables",
|
||||||
partitionKey: this.getPartitionKey(),
|
partitionKey: this.getPartitionKey(),
|
||||||
subPartitionKeys: [],
|
|
||||||
enableDedicatedThroughput: false,
|
enableDedicatedThroughput: false,
|
||||||
createMongoWildCardIndex:
|
createMongoWildCardIndex:
|
||||||
isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport"),
|
isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport"),
|
||||||
useHashV1: false,
|
useHashV2: false,
|
||||||
enableAnalyticalStore: false,
|
enableAnalyticalStore: false,
|
||||||
uniqueKeys: [],
|
uniqueKeys: [],
|
||||||
errorMessage: "",
|
errorMessage: "",
|
||||||
@@ -262,14 +260,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
true
|
true
|
||||||
).toLocaleLowerCase()}.`}
|
).toLocaleLowerCase()}.`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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()}.`}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -345,14 +336,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
true
|
true
|
||||||
).toLocaleLowerCase()} within the database.`}
|
).toLocaleLowerCase()} within the database.`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
iconName="Info"
|
|
||||||
className="panelInfoIcon"
|
|
||||||
tabIndex={0}
|
|
||||||
ariaLabel={`Throughput configured at the database level will be shared across all ${getCollectionName(
|
|
||||||
true
|
|
||||||
).toLocaleLowerCase()} within the database.`}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@@ -400,12 +384,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
|
content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
iconName="Info"
|
|
||||||
className="panelInfoIcon"
|
|
||||||
tabIndex={0}
|
|
||||||
ariaLabel={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</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."
|
"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
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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."
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -542,12 +514,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content={this.getPartitionKeyTooltipText()}
|
content={this.getPartitionKeyTooltipText()}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
iconName="Info"
|
|
||||||
className="panelInfoIcon"
|
|
||||||
tabIndex={0}
|
|
||||||
ariaLabel={this.getPartitionKeyTooltipText()}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</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>
|
</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
|
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.`}
|
billed in addition to the throughput amount you provisioned at the database level.`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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.`}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
@@ -717,18 +603,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
</Text>
|
</Text>
|
||||||
<TooltipHost
|
<TooltipHost
|
||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content={
|
content="Unique keys provide developers with the ability to add a layer of data integrity to their database. By
|
||||||
"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."
|
creating a unique key policy when a container is created, you ensure the uniqueness of one or more values
|
||||||
}
|
per partition key."
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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."
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -791,13 +670,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
directionalHint={DirectionalHint.bottomLeftEdge}
|
||||||
content={this.getAnalyticalStorageTooltipContent()}
|
content={this.getAnalyticalStorageTooltipContent()}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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."
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -874,12 +747,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
directionalHint={DirectionalHint.bottomLeftEdge}
|
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."
|
content="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
|
||||||
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."
|
|
||||||
/>
|
|
||||||
</TooltipHost>
|
</TooltipHost>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
@@ -899,29 +767,18 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{userContext.apiType === "SQL" && (
|
{userContext.apiType === "SQL" && (
|
||||||
<Stack className="panelGroupSpacing">
|
<Checkbox
|
||||||
<Checkbox
|
label="My partition key is larger than 101 bytes"
|
||||||
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)"
|
checked={this.state.useHashV2}
|
||||||
checked={this.state.useHashV1}
|
styles={{
|
||||||
styles={{
|
text: { fontSize: 12 },
|
||||||
text: { fontSize: 12 },
|
checkbox: { width: 12, height: 12 },
|
||||||
checkbox: { width: 12, height: 12 },
|
label: { padding: 0, alignItems: "center" },
|
||||||
label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" },
|
}}
|
||||||
}}
|
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
||||||
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
|
this.setState({ useHashV2: isChecked })
|
||||||
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>
|
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</CollapsibleSectionComponent>
|
</CollapsibleSectionComponent>
|
||||||
@@ -976,20 +833,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName;
|
return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPartitionKeyPlaceHolder(index?: number): string {
|
private getPartitionKeyPlaceHolder(): string {
|
||||||
switch (userContext.apiType) {
|
switch (userContext.apiType) {
|
||||||
case "Mongo":
|
case "Mongo":
|
||||||
return "e.g., address.zipCode";
|
return "e.g., address.zipCode";
|
||||||
case "Gremlin":
|
case "Gremlin":
|
||||||
return "e.g., /address";
|
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:
|
default:
|
||||||
return "e.g., /address/zipCode";
|
return "e.g., /address/zipCode";
|
||||||
}
|
}
|
||||||
@@ -1315,16 +1164,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys();
|
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
|
const partitionKey: DataModels.PartitionKey = partitionKeyString
|
||||||
? {
|
? {
|
||||||
paths: [
|
paths: [partitionKeyString],
|
||||||
partitionKeyString,
|
kind: "Hash",
|
||||||
...(userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0
|
|
||||||
? this.state.subPartitionKeys
|
|
||||||
: []),
|
|
||||||
],
|
|
||||||
kind: userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? "MultiHash" : "Hash",
|
|
||||||
version: partitionKeyVersion,
|
version: partitionKeyVersion,
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoadingFalse();
|
setLoadingFalse();
|
||||||
|
setFormError(error);
|
||||||
const errorMessage = getErrorMessage(error);
|
const errorMessage = getErrorMessage(error);
|
||||||
setFormError(errorMessage);
|
|
||||||
TelemetryProcessor.traceFailure(
|
TelemetryProcessor.traceFailure(
|
||||||
Action.DeleteDatabase,
|
Action.DeleteDatabase,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
|
|||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
{showErrorDetails && (
|
{showErrorDetails && (
|
||||||
<a className="paneErrorLink" role="link" onClick={expandConsole} tabIndex={0} onKeyPress={expandConsole}>
|
<a className="paneErrorLink" role="link" onClick={expandConsole}>
|
||||||
More details
|
More details
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
ariaLabel="A database is analogous to a namespace. It is the unit of management for a set of containers."
|
|
||||||
className="panelInfoIcon"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -125,7 +124,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
ariaLabel="Throughput configured at the database level will be shared across all containers within the database."
|
|
||||||
className="panelInfoIcon"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -165,7 +163,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
ariaLabel="Unique identifier for the container and used for id-based routing through REST and all SDKs."
|
|
||||||
className="panelInfoIcon"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -209,7 +206,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -227,36 +223,13 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
id="addCollection-partitionKeyValue"
|
id="addCollection-partitionKeyValue"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
pattern=".*"
|
pattern=".*"
|
||||||
placeholder="Required - first partition key e.g., /TenantId"
|
placeholder="e.g., /address/zipCode"
|
||||||
required={true}
|
required={true}
|
||||||
size={40}
|
size={40}
|
||||||
title=""
|
title=""
|
||||||
type="text"
|
type="text"
|
||||||
value=""
|
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>
|
<Stack>
|
||||||
<Stack
|
<Stack
|
||||||
@@ -273,7 +246,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -331,7 +303,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
directionalHint={4}
|
directionalHint={4}
|
||||||
>
|
>
|
||||||
<Icon
|
<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"
|
className="panelInfoIcon"
|
||||||
iconName="Info"
|
iconName="Info"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -425,49 +396,26 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
|
|||||||
className="panelGroupSpacing"
|
className="panelGroupSpacing"
|
||||||
id="collapsibleSectionContent"
|
id="collapsibleSectionContent"
|
||||||
>
|
>
|
||||||
<Stack
|
<StyledCheckboxBase
|
||||||
className="panelGroupSpacing"
|
checked={false}
|
||||||
>
|
label="My partition key is larger than 101 bytes"
|
||||||
<StyledCheckboxBase
|
onChange={[Function]}
|
||||||
checked={false}
|
styles={
|
||||||
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)"
|
Object {
|
||||||
onChange={[Function]}
|
"checkbox": Object {
|
||||||
styles={
|
"height": 12,
|
||||||
Object {
|
"width": 12,
|
||||||
"checkbox": Object {
|
},
|
||||||
"height": 12,
|
"label": Object {
|
||||||
"width": 12,
|
"alignItems": "center",
|
||||||
},
|
"padding": 0,
|
||||||
"label": Object {
|
},
|
||||||
"alignItems": "center",
|
"text": Object {
|
||||||
"padding": 0,
|
"fontSize": 12,
|
||||||
"whiteSpace": "break-spaces",
|
},
|
||||||
"wordWrap": "break-word",
|
|
||||||
},
|
|
||||||
"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>
|
</Stack>
|
||||||
</CollapsibleSectionComponent>
|
</CollapsibleSectionComponent>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
TeachingBubble,
|
TeachingBubble,
|
||||||
TeachingBubbleContent,
|
TeachingBubbleContent,
|
||||||
Text
|
Text,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
import { sendMessage } from "Common/MessageHandler";
|
import { sendMessage } from "Common/MessageHandler";
|
||||||
import { MessageTypes } from "Contracts/ExplorerContracts";
|
import { MessageTypes } from "Contracts/ExplorerContracts";
|
||||||
@@ -528,7 +528,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
|||||||
>
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Link>
|
</Link>
|
||||||
<Image src={LinkIcon} alt=" " />
|
<Image src={LinkIcon} />
|
||||||
</Stack>
|
</Stack>
|
||||||
<Text>{item.description}</Text>
|
<Text>{item.description}</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ interface TabsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
|
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
|
||||||
const { openedTabs, openedReactTabs, activeTab, activeReactTab, networkSettingsWarning } = useTabs();
|
const { openedTabs, openedReactTabs, activeTab, activeReactTab, showNetworkSettingsWarning } = useTabs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tabsManagerContainer">
|
<div className="tabsManagerContainer">
|
||||||
{networkSettingsWarning && (
|
{showNetworkSettingsWarning && (
|
||||||
<MessageBar
|
<MessageBar
|
||||||
messageBarType={MessageBarType.warning}
|
messageBarType={MessageBarType.warning}
|
||||||
actions={
|
actions={
|
||||||
@@ -38,7 +38,8 @@ export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
|
|||||||
}
|
}
|
||||||
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
|
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>
|
</MessageBar>
|
||||||
)}
|
)}
|
||||||
<div id="content" className="flexContainer hideOverflows">
|
<div id="content" className="flexContainer hideOverflows">
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export type Features = {
|
|||||||
readonly mongoProxyEndpoint?: string;
|
readonly mongoProxyEndpoint?: string;
|
||||||
readonly mongoProxyAPIs?: string;
|
readonly mongoProxyAPIs?: string;
|
||||||
readonly enableThroughputCap: boolean;
|
readonly enableThroughputCap: boolean;
|
||||||
readonly enableHierarchicalKeys: boolean;
|
|
||||||
|
|
||||||
// can be set via both flight and feature flag
|
// can be set via both flight and feature flag
|
||||||
autoscaleDefault: boolean;
|
autoscaleDefault: boolean;
|
||||||
@@ -91,7 +90,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
||||||
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
||||||
enableThroughputCap: "true" === get("enablethroughputcap"),
|
enableThroughputCap: "true" === get("enablethroughputcap"),
|
||||||
enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,43 +10,31 @@ const PortalIPs: { [key: string]: string[] } = {
|
|||||||
usnat: ["7.28.202.68"],
|
usnat: ["7.28.202.68"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNetworkSettingsWarningMessage = (clientIpAddress: string): string => {
|
export const doNetworkSettingsAllowDataExplorerAccess = (): boolean => {
|
||||||
const accountProperties = userContext.databaseAccount?.properties;
|
const accountProperties = userContext.databaseAccount?.properties;
|
||||||
|
|
||||||
if (!accountProperties) {
|
if (!accountProperties) {
|
||||||
return "";
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public network access is disabled
|
// public network access is disabled
|
||||||
if (accountProperties.publicNetworkAccess !== "Enabled") {
|
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;
|
const ipRules = accountProperties.ipRules;
|
||||||
// public network access is set to "All networks"
|
// public network access is set to "All networks"
|
||||||
if (ipRules.length === 0) {
|
if (ipRules.length === 0) {
|
||||||
return "";
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType === "Cassandra" || userContext.apiType === "Mongo") {
|
const portalIPs = PortalIPs[userContext.portalEnv];
|
||||||
const portalIPs = PortalIPs[userContext.portalEnv];
|
let numberOfMatches = 0;
|
||||||
let numberOfMatches = 0;
|
ipRules.forEach((ipRule) => {
|
||||||
ipRules.forEach((ipRule) => {
|
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
|
||||||
if (portalIPs.indexOf(ipRule.ipAddressOrRange) !== -1) {
|
numberOfMatches++;
|
||||||
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.";
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return "";
|
return numberOfMatches === portalIPs.length;
|
||||||
} 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.";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
import { doNetworkSettingsAllowDataExplorerAccess } from "Utils/NetworkUtility";
|
||||||
import { applyExplorerBindings } from "../applyExplorerBindings";
|
import { applyExplorerBindings } from "../applyExplorerBindings";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { AccountKind, Flights } from "../Common/Constants";
|
import { AccountKind, Flights } from "../Common/Constants";
|
||||||
@@ -382,8 +382,8 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const warningMessage = getNetworkSettingsWarningMessage(inputs.clientIpAddress);
|
const isDataExplorerAccessAllowed = doNetworkSettingsAllowDataExplorerAccess();
|
||||||
useTabs.getState().setNetworkSettingsWarning(warningMessage);
|
useTabs.getState().setShowNetworkSettingsWarning(!isDataExplorerAccessAllowed);
|
||||||
|
|
||||||
if (inputs.features) {
|
if (inputs.features) {
|
||||||
Object.assign(userContext.features, extractFeatures(new URLSearchParams(inputs.features)));
|
Object.assign(userContext.features, extractFeatures(new URLSearchParams(inputs.features)));
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface TabsState {
|
|||||||
openedReactTabs: ReactTabKind[];
|
openedReactTabs: ReactTabKind[];
|
||||||
activeTab: TabsBase | undefined;
|
activeTab: TabsBase | undefined;
|
||||||
activeReactTab: ReactTabKind | undefined;
|
activeReactTab: ReactTabKind | undefined;
|
||||||
networkSettingsWarning: string;
|
showNetworkSettingsWarning: boolean;
|
||||||
activateTab: (tab: TabsBase) => void;
|
activateTab: (tab: TabsBase) => void;
|
||||||
activateNewTab: (tab: TabsBase) => void;
|
activateNewTab: (tab: TabsBase) => void;
|
||||||
activateReactTab: (tabkind: ReactTabKind) => void;
|
activateReactTab: (tabkind: ReactTabKind) => void;
|
||||||
@@ -21,7 +21,7 @@ interface TabsState {
|
|||||||
closeAllNotebookTabs: (hardClose: boolean) => void;
|
closeAllNotebookTabs: (hardClose: boolean) => void;
|
||||||
openAndActivateReactTab: (tabKind: ReactTabKind) => void;
|
openAndActivateReactTab: (tabKind: ReactTabKind) => void;
|
||||||
closeReactTab: (tabKind: ReactTabKind) => void;
|
closeReactTab: (tabKind: ReactTabKind) => void;
|
||||||
setNetworkSettingsWarning: (warningMessage: string) => void;
|
setShowNetworkSettingsWarning: (showWarning: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ReactTabKind {
|
export enum ReactTabKind {
|
||||||
@@ -35,7 +35,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
|||||||
openedReactTabs: [ReactTabKind.Home],
|
openedReactTabs: [ReactTabKind.Home],
|
||||||
activeTab: undefined,
|
activeTab: undefined,
|
||||||
activeReactTab: ReactTabKind.Home,
|
activeReactTab: ReactTabKind.Home,
|
||||||
networkSettingsWarning: "",
|
showNetworkSettingsWarning: false,
|
||||||
activateTab: (tab: TabsBase): void => {
|
activateTab: (tab: TabsBase): void => {
|
||||||
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
|
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
|
||||||
set({ activeTab: tab, activeReactTab: undefined });
|
set({ activeTab: tab, activeReactTab: undefined });
|
||||||
@@ -145,5 +145,5 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
|||||||
|
|
||||||
set({ openedReactTabs: updatedOpenedReactTabs });
|
set({ openedReactTabs: updatedOpenedReactTabs });
|
||||||
},
|
},
|
||||||
setNetworkSettingsWarning: (warningMessage: string) => set({ networkSettingsWarning: warningMessage }),
|
setShowNetworkSettingsWarning: (showWarning: boolean) => set({ showNetworkSettingsWarning: showWarning }),
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user