mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-19 17:01:13 +00:00
Added more Self Serve functionalities (#401)
* added recursion and inition decorators * working version * added todo comment and removed console.log * Added Recursive add * removed type requirement * proper resolution of promises * added custom element and base class * Made selfServe standalone page * Added custom renderer as async type * Added overall defaults * added inital open from data explorer * removed landingpage * added feature for self serve type * renamed sqlx->example and added invalid type * Added comments for Example * removed unnecessary changes * Resolved PR comments Added tests Moved onSubmt and initialize inside base class Moved testExplorer to separate folder made fields of SelfServe Class non static * fixed lint errors * fixed compilation errors * Removed reactbinding changes * renamed dropdown -> choice * Added SelfServeComponent * Addressed PR comments * added toggle, visibility, text display,commandbar * added sqlx example * added onRefrssh * formatting changes * rmoved radioswitch display * updated smartui tests * Added more tests * onSubmit -> onSave * Resolved PR comments
This commit is contained in:
committed by
GitHub
parent
b0b973b21a
commit
49bf8c60db
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import { SmartUiComponent, SmartUiDescriptor, UiType } from "./SmartUiComponent";
|
||||
import { SmartUiComponent, SmartUiDescriptor } from "./SmartUiComponent";
|
||||
import { NumberUiType, SmartUiInput } from "../../../SelfServe/SelfServeTypes";
|
||||
|
||||
describe("SmartUiComponent", () => {
|
||||
const exampleData: SmartUiDescriptor = {
|
||||
@@ -14,6 +15,20 @@ describe("SmartUiComponent", () => {
|
||||
},
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: "description",
|
||||
input: {
|
||||
dataFieldName: "description",
|
||||
type: "string",
|
||||
description: {
|
||||
text: "this is an example description text.",
|
||||
link: {
|
||||
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
||||
text: "Click here for more information.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "throughput",
|
||||
input: {
|
||||
@@ -24,7 +39,7 @@ describe("SmartUiComponent", () => {
|
||||
max: 500,
|
||||
step: 10,
|
||||
defaultValue: 400,
|
||||
uiType: UiType.Spinner,
|
||||
uiType: NumberUiType.Spinner,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -37,7 +52,7 @@ describe("SmartUiComponent", () => {
|
||||
max: 500,
|
||||
step: 10,
|
||||
defaultValue: 400,
|
||||
uiType: UiType.Slider,
|
||||
uiType: NumberUiType.Slider,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -50,7 +65,7 @@ describe("SmartUiComponent", () => {
|
||||
max: 500,
|
||||
step: 10,
|
||||
defaultValue: 400,
|
||||
uiType: UiType.Spinner,
|
||||
uiType: NumberUiType.Spinner,
|
||||
errorMessage: "label, truelabel and falselabel are required for boolean input 'throughput3'",
|
||||
},
|
||||
},
|
||||
@@ -91,11 +106,58 @@ describe("SmartUiComponent", () => {
|
||||
},
|
||||
};
|
||||
|
||||
it("should render", async () => {
|
||||
it("should render and honor input's hidden, disabled state", async () => {
|
||||
const currentValues = new Map<string, SmartUiInput>();
|
||||
const wrapper = shallow(
|
||||
<SmartUiComponent descriptor={exampleData} currentValues={new Map()} onInputChange={undefined} />
|
||||
<SmartUiComponent
|
||||
disabled={false}
|
||||
descriptor={exampleData}
|
||||
currentValues={currentValues}
|
||||
onInputChange={jest.fn()}
|
||||
onError={() => {
|
||||
return;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.exists("#containerId-textField-input")).toBeTruthy();
|
||||
|
||||
currentValues.set("containerId", { value: "container1", hidden: true });
|
||||
wrapper.setProps({ currentValues });
|
||||
wrapper.update();
|
||||
expect(wrapper.exists("#containerId-textField-input")).toBeFalsy();
|
||||
|
||||
currentValues.set("containerId", { value: "container1", hidden: false, disabled: true });
|
||||
wrapper.setProps({ currentValues });
|
||||
wrapper.update();
|
||||
const containerIdTextField = wrapper.find("#containerId-textField-input");
|
||||
expect(containerIdTextField.props().disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it("disable all inputs", async () => {
|
||||
const wrapper = shallow(
|
||||
<SmartUiComponent
|
||||
disabled={true}
|
||||
descriptor={exampleData}
|
||||
currentValues={new Map()}
|
||||
onInputChange={jest.fn()}
|
||||
onError={() => {
|
||||
return;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const throughputSpinner = wrapper.find("#throughput-spinner-input");
|
||||
expect(throughputSpinner.props().disabled).toBeTruthy();
|
||||
const throughput2Slider = wrapper.find("#throughput2-slider-input").childAt(0);
|
||||
expect(throughput2Slider.props().disabled).toBeTruthy();
|
||||
const containerIdTextField = wrapper.find("#containerId-textField-input");
|
||||
expect(containerIdTextField.props().disabled).toBeTruthy();
|
||||
const analyticalStoreToggle = wrapper.find("#analyticalStore-toggle-input");
|
||||
expect(analyticalStoreToggle.props().disabled).toBeTruthy();
|
||||
const databaseDropdown = wrapper.find("#database-dropdown-input");
|
||||
expect(databaseDropdown.props().disabled).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,11 +5,19 @@ import { SpinButton } from "office-ui-fabric-react/lib/SpinButton";
|
||||
import { Dropdown, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { TextField } from "office-ui-fabric-react/lib/TextField";
|
||||
import { Text } from "office-ui-fabric-react/lib/Text";
|
||||
import { RadioSwitchComponent } from "../RadioSwitchComponent/RadioSwitchComponent";
|
||||
import { Stack, IStackTokens } from "office-ui-fabric-react/lib/Stack";
|
||||
import { Link, MessageBar, MessageBarType } from "office-ui-fabric-react";
|
||||
import { Link, MessageBar, MessageBarType, Toggle } from "office-ui-fabric-react";
|
||||
import * as InputUtils from "./InputUtils";
|
||||
import "./SmartUiComponent.less";
|
||||
import {
|
||||
ChoiceItem,
|
||||
Description,
|
||||
Info,
|
||||
InputType,
|
||||
InputTypeValue,
|
||||
NumberUiType,
|
||||
SmartUiInput,
|
||||
} from "../../../SelfServe/SelfServeTypes";
|
||||
|
||||
/**
|
||||
* Generic UX renderer
|
||||
@@ -19,29 +27,14 @@ import "./SmartUiComponent.less";
|
||||
* - a descriptor of the UX.
|
||||
*/
|
||||
|
||||
export type InputTypeValue = "number" | "string" | "boolean" | "object";
|
||||
|
||||
export enum UiType {
|
||||
Spinner = "Spinner",
|
||||
Slider = "Slider",
|
||||
}
|
||||
|
||||
export type ChoiceItem = { label: string; key: string };
|
||||
|
||||
export type InputType = number | string | boolean | ChoiceItem;
|
||||
|
||||
export interface Info {
|
||||
message: string;
|
||||
link?: {
|
||||
href: string;
|
||||
text: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface BaseInput {
|
||||
label: string;
|
||||
interface BaseDisplay {
|
||||
dataFieldName: string;
|
||||
errorMessage?: string;
|
||||
type: InputTypeValue;
|
||||
}
|
||||
|
||||
interface BaseInput extends BaseDisplay {
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
@@ -54,7 +47,7 @@ interface NumberInput extends BaseInput {
|
||||
max: number;
|
||||
step: number;
|
||||
defaultValue?: number;
|
||||
uiType: UiType;
|
||||
uiType: NumberUiType;
|
||||
}
|
||||
|
||||
interface BooleanInput extends BaseInput {
|
||||
@@ -72,12 +65,16 @@ interface ChoiceInput extends BaseInput {
|
||||
defaultKey?: string;
|
||||
}
|
||||
|
||||
type AnyInput = NumberInput | BooleanInput | StringInput | ChoiceInput;
|
||||
interface DescriptionDisplay extends BaseDisplay {
|
||||
description: Description;
|
||||
}
|
||||
|
||||
type AnyDisplay = NumberInput | BooleanInput | StringInput | ChoiceInput | DescriptionDisplay;
|
||||
|
||||
interface Node {
|
||||
id: string;
|
||||
info?: Info;
|
||||
input?: AnyInput;
|
||||
input?: AnyDisplay;
|
||||
children?: Node[];
|
||||
}
|
||||
|
||||
@@ -86,11 +83,12 @@ export interface SmartUiDescriptor {
|
||||
}
|
||||
|
||||
/************************** Component implementation starts here ************************************* */
|
||||
|
||||
export interface SmartUiComponentProps {
|
||||
descriptor: SmartUiDescriptor;
|
||||
currentValues: Map<string, InputType>;
|
||||
onInputChange: (input: AnyInput, newValue: InputType) => void;
|
||||
currentValues: Map<string, SmartUiInput>;
|
||||
onInputChange: (input: AnyDisplay, newValue: InputType) => void;
|
||||
onError: (hasError: boolean) => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
interface SmartUiComponentState {
|
||||
@@ -98,12 +96,22 @@ interface SmartUiComponentState {
|
||||
}
|
||||
|
||||
export class SmartUiComponent extends React.Component<SmartUiComponentProps, SmartUiComponentState> {
|
||||
private shouldCheckErrors = true;
|
||||
private static readonly labelStyle = {
|
||||
color: "#393939",
|
||||
fontFamily: "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
fontSize: 12,
|
||||
};
|
||||
|
||||
componentDidUpdate(): void {
|
||||
if (!this.shouldCheckErrors) {
|
||||
this.shouldCheckErrors = true;
|
||||
return;
|
||||
}
|
||||
this.props.onError(this.state.errors.size > 0);
|
||||
this.shouldCheckErrors = false;
|
||||
}
|
||||
|
||||
constructor(props: SmartUiComponentProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -113,7 +121,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
|
||||
private renderInfo(info: Info): JSX.Element {
|
||||
return (
|
||||
<MessageBar>
|
||||
<MessageBar styles={{ root: { width: 400 } }}>
|
||||
{info.message}
|
||||
{info.link && (
|
||||
<Link href={info.link.href} target="_blank">
|
||||
@@ -125,17 +133,20 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
}
|
||||
|
||||
private renderTextInput(input: StringInput): JSX.Element {
|
||||
const value = this.props.currentValues.get(input.dataFieldName) as string;
|
||||
const value = this.props.currentValues.get(input.dataFieldName)?.value as string;
|
||||
const disabled = this.props.disabled || this.props.currentValues.get(input.dataFieldName)?.disabled;
|
||||
return (
|
||||
<div className="stringInputContainer">
|
||||
<TextField
|
||||
id={`${input.dataFieldName}-textBox-input`}
|
||||
id={`${input.dataFieldName}-textField-input`}
|
||||
label={input.label}
|
||||
type="text"
|
||||
value={value}
|
||||
value={value || ""}
|
||||
placeholder={input.placeholder}
|
||||
disabled={disabled}
|
||||
onChange={(_, newValue) => this.props.onInputChange(input, newValue)}
|
||||
styles={{
|
||||
root: { width: 400 },
|
||||
subComponentStyles: {
|
||||
label: {
|
||||
root: {
|
||||
@@ -150,13 +161,27 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
);
|
||||
}
|
||||
|
||||
private renderDescription(input: DescriptionDisplay): JSX.Element {
|
||||
const description = input.description;
|
||||
return (
|
||||
<Text id={`${input.dataFieldName}-text-display`}>
|
||||
{input.description.text}{" "}
|
||||
{description.link && (
|
||||
<Link target="_blank" href={input.description.link.href}>
|
||||
{input.description.link.text}
|
||||
</Link>
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
private clearError(dataFieldName: string): void {
|
||||
const { errors } = this.state;
|
||||
errors.delete(dataFieldName);
|
||||
this.setState({ errors });
|
||||
}
|
||||
|
||||
private onValidate = (input: AnyInput, value: string, min: number, max: number): string => {
|
||||
private onValidate = (input: NumberInput, value: string, min: number, max: number): string => {
|
||||
const newValue = InputUtils.onValidateValueChange(value, min, max);
|
||||
const dataFieldName = input.dataFieldName;
|
||||
if (newValue) {
|
||||
@@ -165,13 +190,13 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
return newValue.toString();
|
||||
} else {
|
||||
const { errors } = this.state;
|
||||
errors.set(dataFieldName, `Invalid value ${value}: must be between ${min} and ${max}`);
|
||||
errors.set(dataFieldName, `Invalid value '${value}'. It must be between ${min} and ${max}`);
|
||||
this.setState({ errors });
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
private onIncrement = (input: AnyInput, value: string, step: number, max: number): string => {
|
||||
private onIncrement = (input: NumberInput, value: string, step: number, max: number): string => {
|
||||
const newValue = InputUtils.onIncrementValue(value, step, max);
|
||||
const dataFieldName = input.dataFieldName;
|
||||
if (newValue) {
|
||||
@@ -182,7 +207,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
return undefined;
|
||||
};
|
||||
|
||||
private onDecrement = (input: AnyInput, value: string, step: number, min: number): string => {
|
||||
private onDecrement = (input: NumberInput, value: string, step: number, min: number): string => {
|
||||
const newValue = InputUtils.onDecrementValue(value, step, min);
|
||||
const dataFieldName = input.dataFieldName;
|
||||
if (newValue) {
|
||||
@@ -203,10 +228,11 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
step: step,
|
||||
};
|
||||
|
||||
const value = this.props.currentValues.get(dataFieldName) as number;
|
||||
if (input.uiType === UiType.Spinner) {
|
||||
const value = this.props.currentValues.get(dataFieldName)?.value as number;
|
||||
const disabled = this.props.disabled || this.props.currentValues.get(dataFieldName)?.disabled;
|
||||
if (input.uiType === NumberUiType.Spinner) {
|
||||
return (
|
||||
<>
|
||||
<Stack styles={{ root: { width: 400 } }} tokens={{ childrenGap: 2 }}>
|
||||
<SpinButton
|
||||
{...props}
|
||||
id={`${input.dataFieldName}-spinner-input`}
|
||||
@@ -215,6 +241,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
onIncrement={(newValue) => this.onIncrement(input, newValue, props.step, props.max)}
|
||||
onDecrement={(newValue) => this.onDecrement(input, newValue, props.step, props.min)}
|
||||
labelPosition={Position.top}
|
||||
disabled={disabled}
|
||||
styles={{
|
||||
label: {
|
||||
...SmartUiComponent.labelStyle,
|
||||
@@ -225,16 +252,18 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
{this.state.errors.has(dataFieldName) && (
|
||||
<MessageBar messageBarType={MessageBarType.error}>Error: {this.state.errors.get(dataFieldName)}</MessageBar>
|
||||
)}
|
||||
</>
|
||||
</Stack>
|
||||
);
|
||||
} else if (input.uiType === UiType.Slider) {
|
||||
} else if (input.uiType === NumberUiType.Slider) {
|
||||
return (
|
||||
<div id={`${input.dataFieldName}-slider-input`}>
|
||||
<Slider
|
||||
{...props}
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
onChange={(newValue) => this.props.onInputChange(input, newValue)}
|
||||
styles={{
|
||||
root: { width: 400 },
|
||||
titleLabel: {
|
||||
...SmartUiComponent.labelStyle,
|
||||
fontWeight: 600,
|
||||
@@ -250,49 +279,44 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
}
|
||||
|
||||
private renderBooleanInput(input: BooleanInput): JSX.Element {
|
||||
const value = this.props.currentValues.get(input.dataFieldName) as boolean;
|
||||
const selectedKey = value || input.defaultValue ? "true" : "false";
|
||||
const value = this.props.currentValues.get(input.dataFieldName)?.value as boolean;
|
||||
const disabled = this.props.disabled || this.props.currentValues.get(input.dataFieldName)?.disabled;
|
||||
return (
|
||||
<div id={`${input.dataFieldName}-radioSwitch-input`}>
|
||||
<div className="inputLabelContainer">
|
||||
<Text variant="small" nowrap className="inputLabel">
|
||||
{input.label}
|
||||
</Text>
|
||||
</div>
|
||||
<RadioSwitchComponent
|
||||
choices={[
|
||||
{
|
||||
label: input.falseLabel,
|
||||
key: "false",
|
||||
onSelect: () => this.props.onInputChange(input, false),
|
||||
},
|
||||
{
|
||||
label: input.trueLabel,
|
||||
key: "true",
|
||||
onSelect: () => this.props.onInputChange(input, true),
|
||||
},
|
||||
]}
|
||||
selectedKey={selectedKey}
|
||||
/>
|
||||
</div>
|
||||
<Toggle
|
||||
id={`${input.dataFieldName}-toggle-input`}
|
||||
label={input.label}
|
||||
checked={value || false}
|
||||
onText={input.trueLabel}
|
||||
offText={input.falseLabel}
|
||||
disabled={disabled}
|
||||
onChange={(event, checked: boolean) => this.props.onInputChange(input, checked)}
|
||||
styles={{ root: { width: 400 } }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderChoiceInput(input: ChoiceInput): JSX.Element {
|
||||
const { label, defaultKey: defaultKey, dataFieldName, choices, placeholder } = input;
|
||||
const value = this.props.currentValues.get(dataFieldName) as string;
|
||||
const value = this.props.currentValues.get(dataFieldName)?.value as string;
|
||||
const disabled = this.props.disabled || this.props.currentValues.get(dataFieldName)?.disabled;
|
||||
let selectedKey = value ? value : defaultKey;
|
||||
if (!selectedKey) {
|
||||
selectedKey = "";
|
||||
}
|
||||
return (
|
||||
<Dropdown
|
||||
id={`${input.dataFieldName}-dropown-input`}
|
||||
id={`${input.dataFieldName}-dropdown-input`}
|
||||
label={label}
|
||||
selectedKey={value ? value : defaultKey}
|
||||
selectedKey={selectedKey}
|
||||
onChange={(_, item: IDropdownOption) => this.props.onInputChange(input, item.key.toString())}
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
options={choices.map((c) => ({
|
||||
key: c.key,
|
||||
text: c.label,
|
||||
}))}
|
||||
styles={{
|
||||
root: { width: 400 },
|
||||
label: {
|
||||
...SmartUiComponent.labelStyle,
|
||||
fontWeight: 600,
|
||||
@@ -303,16 +327,23 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
);
|
||||
}
|
||||
|
||||
private renderError(input: AnyInput): JSX.Element {
|
||||
private renderError(input: AnyDisplay): JSX.Element {
|
||||
return <MessageBar messageBarType={MessageBarType.error}>Error: {input.errorMessage}</MessageBar>;
|
||||
}
|
||||
|
||||
private renderInput(input: AnyInput): JSX.Element {
|
||||
private renderDisplay(input: AnyDisplay): JSX.Element {
|
||||
if (input.errorMessage) {
|
||||
return this.renderError(input);
|
||||
}
|
||||
const inputHidden = this.props.currentValues.get(input.dataFieldName)?.hidden;
|
||||
if (inputHidden) {
|
||||
return <></>;
|
||||
}
|
||||
switch (input.type) {
|
||||
case "string":
|
||||
if ("description" in input) {
|
||||
return this.renderDescription(input as DescriptionDisplay);
|
||||
}
|
||||
return this.renderTextInput(input as StringInput);
|
||||
case "number":
|
||||
return this.renderNumberInput(input as NumberInput);
|
||||
@@ -326,13 +357,13 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
}
|
||||
|
||||
private renderNode(node: Node): JSX.Element {
|
||||
const containerStackTokens: IStackTokens = { childrenGap: 15 };
|
||||
const containerStackTokens: IStackTokens = { childrenGap: 10 };
|
||||
|
||||
return (
|
||||
<Stack tokens={containerStackTokens} className="widgetRendererContainer">
|
||||
<Stack.Item>
|
||||
{node.info && this.renderInfo(node.info as Info)}
|
||||
{node.input && this.renderInput(node.input)}
|
||||
{node.input && this.renderDisplay(node.input)}
|
||||
</Stack.Item>
|
||||
{node.children && node.children.map((child) => <div key={child.id}>{this.renderNode(child)}</div>)}
|
||||
</Stack>
|
||||
@@ -340,11 +371,6 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const containerStackTokens: IStackTokens = { childrenGap: 20 };
|
||||
return (
|
||||
<Stack tokens={containerStackTokens} styles={{ root: { width: 400, padding: 10 } }}>
|
||||
{this.renderNode(this.props.descriptor.root)}
|
||||
</Stack>
|
||||
);
|
||||
return this.renderNode(this.props.descriptor.root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +1,405 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SmartUiComponent should render 1`] = `
|
||||
exports[`SmartUiComponent disable all inputs 1`] = `
|
||||
<Stack
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"padding": 10,
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 20,
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledMessageBarBase>
|
||||
Start at $24/mo per database
|
||||
<StyledLinkBase
|
||||
href="https://aka.ms/azure-cosmos-db-pricing"
|
||||
target="_blank"
|
||||
>
|
||||
More Details
|
||||
</StyledLinkBase>
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
<div
|
||||
key="throughput"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
<StackItem>
|
||||
<StyledMessageBarBase
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
Start at $24/mo per database
|
||||
<StyledLinkBase
|
||||
href="https://aka.ms/azure-cosmos-db-pricing"
|
||||
target="_blank"
|
||||
>
|
||||
<StackItem>
|
||||
More Details
|
||||
</StyledLinkBase>
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
<div
|
||||
key="description"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<Text
|
||||
id="description-text-display"
|
||||
>
|
||||
this is an example description text.
|
||||
|
||||
<StyledLinkBase
|
||||
href="https://docs.microsoft.com/en-us/azure/cosmos-db/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
Click here for more information.
|
||||
</StyledLinkBase>
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<Stack
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<CustomizedSpinButton
|
||||
ariaLabel="Throughput (input)"
|
||||
decrementButtonIcon={
|
||||
Object {
|
||||
"iconName": "ChevronDownSmall",
|
||||
}
|
||||
}
|
||||
disabled={true}
|
||||
id="throughput-spinner-input"
|
||||
incrementButtonIcon={
|
||||
Object {
|
||||
"iconName": "ChevronUpSmall",
|
||||
}
|
||||
}
|
||||
label="Throughput (input)"
|
||||
labelPosition={0}
|
||||
max={500}
|
||||
min={400}
|
||||
onDecrement={[Function]}
|
||||
onIncrement={[Function]}
|
||||
onValidate={[Function]}
|
||||
step={10}
|
||||
styles={
|
||||
Object {
|
||||
"label": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput2"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
id="throughput2-slider-input"
|
||||
>
|
||||
<StyledSliderBase
|
||||
ariaLabel="Throughput (Slider)"
|
||||
disabled={true}
|
||||
label="Throughput (Slider)"
|
||||
max={500}
|
||||
min={400}
|
||||
onChange={[Function]}
|
||||
step={10}
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
"titleLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
"valueLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput3"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledMessageBarBase
|
||||
messageBarType={1}
|
||||
>
|
||||
Error:
|
||||
label, truelabel and falselabel are required for boolean input 'throughput3'
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="containerId"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
className="stringInputContainer"
|
||||
>
|
||||
<StyledTextFieldBase
|
||||
disabled={true}
|
||||
id="containerId-textField-input"
|
||||
label="Container id"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
"subComponentStyles": Object {
|
||||
"label": Object {
|
||||
"root": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="analyticalStore"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledToggleBase
|
||||
checked={false}
|
||||
disabled={true}
|
||||
id="analyticalStore-toggle-input"
|
||||
label="Analytical Store"
|
||||
offText="Disabled"
|
||||
onChange={[Function]}
|
||||
onText="Enabled"
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="database"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledWithResponsiveMode
|
||||
disabled={true}
|
||||
id="database-dropdown-input"
|
||||
label="Database"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"key": "db1",
|
||||
"text": "Database 1",
|
||||
},
|
||||
Object {
|
||||
"key": "db2",
|
||||
"text": "Database 2",
|
||||
},
|
||||
Object {
|
||||
"key": "db3",
|
||||
"text": "Database 3",
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedKey="db2"
|
||||
styles={
|
||||
Object {
|
||||
"dropdown": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
},
|
||||
"label": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
exports[`SmartUiComponent should render and honor input's hidden, disabled state 1`] = `
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledMessageBarBase
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
Start at $24/mo per database
|
||||
<StyledLinkBase
|
||||
href="https://aka.ms/azure-cosmos-db-pricing"
|
||||
target="_blank"
|
||||
>
|
||||
More Details
|
||||
</StyledLinkBase>
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
<div
|
||||
key="description"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<Text
|
||||
id="description-text-display"
|
||||
>
|
||||
this is an example description text.
|
||||
|
||||
<StyledLinkBase
|
||||
href="https://docs.microsoft.com/en-us/azure/cosmos-db/introduction"
|
||||
target="_blank"
|
||||
>
|
||||
Click here for more information.
|
||||
</StyledLinkBase>
|
||||
</Text>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<Stack
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 2,
|
||||
}
|
||||
}
|
||||
>
|
||||
<CustomizedSpinButton
|
||||
ariaLabel="Throughput (input)"
|
||||
decrementButtonIcon={
|
||||
@@ -80,210 +433,203 @@ exports[`SmartUiComponent should render 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput2"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
</Stack>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput2"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
id="throughput2-slider-input"
|
||||
>
|
||||
<StyledSliderBase
|
||||
ariaLabel="Throughput (Slider)"
|
||||
label="Throughput (Slider)"
|
||||
max={500}
|
||||
min={400}
|
||||
onChange={[Function]}
|
||||
step={10}
|
||||
styles={
|
||||
Object {
|
||||
"titleLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
"valueLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput3"
|
||||
}
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledMessageBarBase
|
||||
messageBarType={1}
|
||||
>
|
||||
Error:
|
||||
label, truelabel and falselabel are required for boolean input 'throughput3'
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="containerId"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
className="stringInputContainer"
|
||||
>
|
||||
<StyledTextFieldBase
|
||||
id="containerId-textBox-input"
|
||||
label="Container id"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"subComponentStyles": Object {
|
||||
"label": Object {
|
||||
"root": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="analyticalStore"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
id="analyticalStore-radioSwitch-input"
|
||||
>
|
||||
<div
|
||||
className="inputLabelContainer"
|
||||
>
|
||||
<Text
|
||||
className="inputLabel"
|
||||
nowrap={true}
|
||||
variant="small"
|
||||
>
|
||||
Analytical Store
|
||||
</Text>
|
||||
</div>
|
||||
<RadioSwitchComponent
|
||||
choices={
|
||||
Array [
|
||||
Object {
|
||||
"key": "false",
|
||||
"label": "Disabled",
|
||||
"onSelect": [Function],
|
||||
},
|
||||
Object {
|
||||
"key": "true",
|
||||
"label": "Enabled",
|
||||
"onSelect": [Function],
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedKey="true"
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="database"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 15,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledWithResponsiveMode
|
||||
id="database-dropown-input"
|
||||
label="Database"
|
||||
<StackItem>
|
||||
<div
|
||||
id="throughput2-slider-input"
|
||||
>
|
||||
<StyledSliderBase
|
||||
ariaLabel="Throughput (Slider)"
|
||||
label="Throughput (Slider)"
|
||||
max={500}
|
||||
min={400}
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"key": "db1",
|
||||
"text": "Database 1",
|
||||
},
|
||||
Object {
|
||||
"key": "db2",
|
||||
"text": "Database 2",
|
||||
},
|
||||
Object {
|
||||
"key": "db3",
|
||||
"text": "Database 3",
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedKey="db2"
|
||||
step={10}
|
||||
styles={
|
||||
Object {
|
||||
"dropdown": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
"label": Object {
|
||||
"titleLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
"valueLabel": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
</Stack>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="throughput3"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledMessageBarBase
|
||||
messageBarType={1}
|
||||
>
|
||||
Error:
|
||||
label, truelabel and falselabel are required for boolean input 'throughput3'
|
||||
</StyledMessageBarBase>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="containerId"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<div
|
||||
className="stringInputContainer"
|
||||
>
|
||||
<StyledTextFieldBase
|
||||
id="containerId-textField-input"
|
||||
label="Container id"
|
||||
onChange={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
"subComponentStyles": Object {
|
||||
"label": Object {
|
||||
"root": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="analyticalStore"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledToggleBase
|
||||
checked={false}
|
||||
id="analyticalStore-toggle-input"
|
||||
label="Analytical Store"
|
||||
offText="Disabled"
|
||||
onChange={[Function]}
|
||||
onText="Enabled"
|
||||
styles={
|
||||
Object {
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
<div
|
||||
key="database"
|
||||
>
|
||||
<Stack
|
||||
className="widgetRendererContainer"
|
||||
tokens={
|
||||
Object {
|
||||
"childrenGap": 10,
|
||||
}
|
||||
}
|
||||
>
|
||||
<StackItem>
|
||||
<StyledWithResponsiveMode
|
||||
id="database-dropdown-input"
|
||||
label="Database"
|
||||
onChange={[Function]}
|
||||
options={
|
||||
Array [
|
||||
Object {
|
||||
"key": "db1",
|
||||
"text": "Database 1",
|
||||
},
|
||||
Object {
|
||||
"key": "db2",
|
||||
"text": "Database 2",
|
||||
},
|
||||
Object {
|
||||
"key": "db3",
|
||||
"text": "Database 3",
|
||||
},
|
||||
]
|
||||
}
|
||||
selectedKey="db2"
|
||||
styles={
|
||||
Object {
|
||||
"dropdown": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
},
|
||||
"label": Object {
|
||||
"color": "#393939",
|
||||
"fontFamily": "wf_segoe-ui_normal, 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif",
|
||||
"fontSize": 12,
|
||||
"fontWeight": 600,
|
||||
},
|
||||
"root": Object {
|
||||
"width": 400,
|
||||
},
|
||||
}
|
||||
}
|
||||
/>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</div>
|
||||
</Stack>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user