proper resolution of promises

This commit is contained in:
Srinath Narayanan 2020-12-03 01:11:07 -08:00
parent 4381ea447c
commit 2dbde9c31a
7 changed files with 226 additions and 171 deletions

View File

@ -17,7 +17,7 @@ export const SmartUi = (): ClassDecorator => {
};
};
export const ClassInfo = (info: Info): ClassDecorator => {
export const ClassInfo = (info: (() => Promise<Info>) | Info): ClassDecorator => {
return (target: Function) => {
addPropertyToMap(target, "root", target.name, "info", info);
};

View File

@ -1,11 +1,13 @@
import { EnumItem, Info, InputType } from "../../../SmartUi/SmartUiComponent";
import { ChoiceItem, Info, InputType } from "../../../SmartUi/SmartUiComponent";
import { addPropertyToMap } from "./SelfServeUtils";
const addToMap = (descriptorName: string, descriptorValue: any): PropertyDecorator => {
return (target, property) => {
const className = (target as Function).name;
var propertyType = Reflect.getMetadata("design:type", target, property);
addPropertyToMap(target, property.toString(), className, "type", propertyType.name);
var propertyType = (Reflect.getMetadata("design:type", target, property).name as string).toLowerCase();
addPropertyToMap(target, property.toString(), className, "type", propertyType);
addPropertyToMap(target, property.toString(), className, "dataFieldName", property.toString());
if (!className) {
throw new Error("property descriptor applied to non static field!");
@ -20,11 +22,11 @@ export const OnChange = (
return addToMap("onChange", onChange);
};
export const PropertyInfo = (info: Info): PropertyDecorator => {
export const PropertyInfo = (info: (() => Promise<Info>) | Info): PropertyDecorator => {
return addToMap("info", info);
};
export const Placeholder = (placeholder: string): PropertyDecorator => {
export const Placeholder = (placeholder: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("placeholder", placeholder);
};
@ -32,43 +34,47 @@ export const ParentOf = (children: string[]): PropertyDecorator => {
return addToMap("parentOf", children);
};
export const Label = (label: string): PropertyDecorator => {
export const Label = (label: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("label", label);
};
export const DataFieldName = (dataFieldName: string): PropertyDecorator => {
return addToMap("dataFieldName", dataFieldName);
};
export const Min = (min: number): PropertyDecorator => {
export const Min = (min: (() => Promise<number>) | number): PropertyDecorator => {
return addToMap("min", min);
};
export const Max = (max: number): PropertyDecorator => {
export const Max = (max: (() => Promise<number>) | number): PropertyDecorator => {
return addToMap("max", max);
};
export const Step = (step: number): PropertyDecorator => {
export const Step = (step: (() => Promise<number>) | number): PropertyDecorator => {
return addToMap("step", step);
};
export const DefaultValue = (defaultValue: any): PropertyDecorator => {
return addToMap("defaultValue", defaultValue);
export const DefaultStringValue = (defaultStringValue: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("defaultValue", defaultStringValue);
};
export const TrueLabel = (trueLabel: string): PropertyDecorator => {
export const DefaultNumberValue = (defaultNumberValue: (() => Promise<number>) | number): PropertyDecorator => {
return addToMap("defaultValue", defaultNumberValue);
};
export const DefaultBooleanValue = (defaultBooleanValue: (() => Promise<boolean>) | boolean): PropertyDecorator => {
return addToMap("defaultValue", defaultBooleanValue);
};
export const TrueLabel = (trueLabel: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("trueLabel", trueLabel);
};
export const FalseLabel = (falseLabel: string): PropertyDecorator => {
export const FalseLabel = (falseLabel: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("falseLabel", falseLabel);
};
export const Choices = (choices: EnumItem[]): PropertyDecorator => {
export const Choices = (choices: (() => Promise<ChoiceItem[]>) | ChoiceItem[]): PropertyDecorator => {
return addToMap("choices", choices);
};
export const DefaultKey = (defaultKey: string): PropertyDecorator => {
export const DefaultKey = (defaultKey: (() => Promise<string>) | string): PropertyDecorator => {
return addToMap("defaultKey", defaultKey);
};

View File

@ -24,7 +24,7 @@ export class SelfServeCmponent extends React.Component {
input: {
label: "Instance Count",
dataFieldName: "instanceCount",
type: "Number",
type: "number",
min: 1,
max: 5,
step: 1,
@ -44,7 +44,7 @@ export class SelfServeCmponent extends React.Component {
input: {
label: "Instance Size",
dataFieldName: "instanceSize",
type: "Object",
type: "object",
choices: [
{ label: "1Core4Gb", key: "1Core4Gb", value: "1Core4Gb" },
{ label: "2Core8Gb", key: "2Core8Gb", value: "2Core8Gb" },

View File

@ -1,6 +1,6 @@
import "reflect-metadata";
import {
EnumItem,
ChoiceItem,
Node,
Info,
InputTypeValue,
@ -9,26 +9,26 @@ import {
NumberInput,
StringInput,
BooleanInput,
EnumInput,
ChoiceInput,
InputType
} from "../../../SmartUi/SmartUiComponent";
export interface CommonInputTypes {
id: string;
info?: Info;
info?: (() => Promise<Info>) | Info;
parentOf?: string[];
type?: InputTypeValue;
label?: string;
placeholder?: string;
label?: (() => Promise<string>) | string;
placeholder?: (() => Promise<string>) | string;
dataFieldName?: string;
min?: number;
max?: number;
step?: number;
min?: (() => Promise<number>) | number;
max?: (() => Promise<number>) | number;
step?: (() => Promise<number>) | number;
defaultValue?: any;
trueLabel?: string;
falseLabel?: string;
choices?: EnumItem[];
defaultKey?: string;
trueLabel?: (() => Promise<string>) | string;
falseLabel?: (() => Promise<string>) | string;
choices?: (() => Promise<ChoiceItem[]>) | ChoiceItem[];
defaultKey?: (() => Promise<string>) | string;
inputType?: string;
onChange?: (currentState: Map<string, InputType>, newValue: InputType) => Map<string, InputType>;
onSubmit?: (currentValues: Map<string, InputType>) => Promise<void>;
@ -72,7 +72,7 @@ export const addPropertyToMap = (
propertyObject = { id: propertyKey };
}
if (getValue(descriptorKey, propertyObject) && descriptorKey !== "type") {
if (getValue(descriptorKey, propertyObject) && descriptorKey !== "type" && descriptorKey !== "dataFieldName") {
throw new Error("duplicate descriptor");
}
@ -82,42 +82,6 @@ export const addPropertyToMap = (
Reflect.defineMetadata(metadataKey, context, target);
};
/*
const modifyParentProperty = (children: {[key: string]: any}, parentProperty: string, property: string | symbol) : any => {
if (parentProperty in children) {
children[parentProperty][property] ={id: property, input: {}}
return children
} else {
const keys = Object.keys(children)
for(var i =0; i< keys.length; i++) {
children[keys[i]] = modifyParentProperty(children[keys[i]], parentProperty, property)
return children
}
}
return children
}
export const PropertyParser = (metadataKey: string, parentProperty?: string): PropertyDecorator => {
return (target, property) => {
let context = Reflect.getMetadata(metadataKey, target)
if(!context) {
context = {id: "root", info: undefined, input: undefined, children: {} }
context.children[property] = {id: property, input: {}}
}
if (parentProperty) {
const prevContextValue = JSON.stringify(context)
context.children = modifyParentProperty(context.children, parentProperty, property)
if (JSON.stringify(context) === prevContextValue) {
throw new Error(`${parentProperty} not defined. declare it before the child property with @Property decorator.`)
}
} else {
context.children[property] = {id: property, input: {}}
}
Reflect.defineMetadata(metadataKey, context, target)
};
};
*/
export const toSmartUiDescriptor = (metadataKey: string, target: Object): void => {
const context = Reflect.getMetadata(metadataKey, target) as Map<String, CommonInputTypes>;
Reflect.defineMetadata(metadataKey, context, target);
@ -125,7 +89,7 @@ export const toSmartUiDescriptor = (metadataKey: string, target: Object): void =
const root = context.get("root");
context.delete("root");
if (!root || !("onSubmit" in root)) {
if (!root?.onSubmit) {
throw new Error(
"@OnSubmit decorator not declared for the class. Please ensure @SmartUi is the first decorator used for the class."
);
@ -157,12 +121,12 @@ const addToDescriptor = (
let value = context.get(key);
if (!value) {
// should already be added to root
value = getChildFromRoot(key, smartUiDescriptor);
if (!value) {
const childNode = getChildFromRoot(key, smartUiDescriptor);
if (!childNode) {
// if not found at root level, error out
throw new Error("Either child does not exist or child has been assigned to more than one parent");
}
root.children.push(value);
root.children.push(childNode);
return;
}
@ -180,7 +144,7 @@ const addToDescriptor = (
root.children.push(element);
};
const getChildFromRoot = (key: String, smartUiDescriptor: Descriptor): CommonInputTypes => {
const getChildFromRoot = (key: String, smartUiDescriptor: Descriptor): Node => {
let i = 0;
const children = smartUiDescriptor.root.children;
for (; i < children.length; i++) {
@ -197,16 +161,16 @@ const getInput = (value: CommonInputTypes): AnyInput => {
if (!value.label || !value.type || !value.dataFieldName) {
throw new Error("label, onChange, type and dataFieldName are required.");
}
console.log(value.type);
switch (value.type) {
case "Number":
case "number":
if (!value.step || !value.defaultValue || !value.inputType) {
throw new Error("step, defaultValue and inputType are needed for number type");
}
return value as NumberInput;
case "String":
case "string":
return value as StringInput;
case "Boolean":
case "boolean":
if (!value.trueLabel || !value.falseLabel || value.defaultValue === undefined) {
throw new Error("truelabel, falselabel and defaultValue are needed for boolean type");
}
@ -215,6 +179,6 @@ const getInput = (value: CommonInputTypes): AnyInput => {
if (!value.choices || !value.defaultKey) {
throw new Error("choices and defaultKey are needed for enum type");
}
return value as EnumInput;
return value as ChoiceInput;
}
};

View File

@ -1,11 +1,9 @@
import {
DataFieldName,
Label,
Min,
Max,
Step,
DefaultKey,
DefaultValue,
NumberInputType,
Choices,
ParentOf,
@ -13,11 +11,23 @@ import {
OnChange,
TrueLabel,
FalseLabel,
Placeholder
Placeholder,
DefaultNumberValue,
DefaultBooleanValue,
DefaultStringValue
} from "./PropertyDescriptors";
import { Descriptor, EnumItem, Info, InputType } from "../../../SmartUi/SmartUiComponent";
import { Descriptor, ChoiceItem, Info, InputType } from "../../../SmartUi/SmartUiComponent";
import { SmartUi, ClassInfo, SelfServeClass, OnSubmit } from "./ClassDescriptors";
const getPromise = <T extends (number | string | boolean | ChoiceItem[] | Info)>(value: T) : () => Promise<T> => {
const f = async () : Promise<T> => {
console.log("delay start")
await SqlX.delay(100)
console.log("delay end")
return value
}
return f
}
enum Sizes {
OneCore4Gb = "OneCore4Gb",
TwoCore8Gb = "TwoCore8Gb",
@ -25,41 +35,43 @@ enum Sizes {
}
@SmartUi()
@ClassInfo(SqlX.sqlXInfo)
@OnSubmit(SqlX.onSubmit)
@SelfServeClass()
@ClassInfo(getPromise(SqlX.sqlXInfo))
@OnSubmit(SqlX.onSubmit)
export class SqlX {
@PropertyInfo(SqlX.instanceSizeInfo)
@Label("Instance Size")
@DataFieldName("instanceSize")
@Choices(SqlX.instanceSizeOptions)
@DefaultKey(Sizes.OneCore4Gb)
static instanceSize: EnumItem;
public static toSmartUiDescriptor = (): Descriptor => {
return Reflect.getMetadata(SqlX.name, SqlX) as Descriptor;
};
@PropertyInfo(getPromise(SqlX.instanceSizeInfo))
@Label(getPromise("Instance Size"))
@Choices(getPromise(SqlX.instanceSizeOptions))
@DefaultKey(getPromise(Sizes.OneCore4Gb))
static instanceSize: ChoiceItem;
@OnChange(SqlX.onInstanceCountChange)
@Label("Instance Count")
@DataFieldName("instanceCount")
@Min(1)
@Max(5)
@Step(1)
@DefaultValue(1)
@Label(getPromise("Instance Count"))
@Min(getPromise(0))
@Max(getPromise(5))
@Step(getPromise(1))
@DefaultNumberValue(getPromise(1))
@NumberInputType("slider")
@ParentOf(["instanceSize", "instanceName", "isAllowed"])
static instanceCount: number;
@Label("Feature Allowed")
@DataFieldName("isAllowed")
@DefaultValue(false)
@TrueLabel("allowed")
@FalseLabel("not allowed")
@Label(getPromise("Feature Allowed"))
@DefaultBooleanValue(getPromise(false))
@TrueLabel(getPromise("allowed"))
@FalseLabel(getPromise("not allowed"))
static isAllowed: boolean;
@Label("Instance Name")
@DataFieldName("instanceName")
@Placeholder("instance name")
@Label(getPromise("Instance Name"))
@DefaultStringValue(getPromise("asdf"))
@Placeholder(getPromise("instance name"))
static instanceName: string;
static instanceSizeOptions: EnumItem[] = [
static instanceSizeOptions: ChoiceItem[] = [
{ label: Sizes.OneCore4Gb, key: Sizes.OneCore4Gb, value: Sizes.OneCore4Gb },
{ label: Sizes.TwoCore8Gb, key: Sizes.TwoCore8Gb, value: Sizes.TwoCore8Gb },
{ label: Sizes.FourCore16Gb, key: Sizes.FourCore16Gb, value: Sizes.FourCore16Gb }
@ -97,7 +109,8 @@ export class SqlX {
);
};
public static toSmartUiDescriptor = (): Descriptor => {
return Reflect.getMetadata(SqlX.name, SqlX) as Descriptor;
};
static delay = (ms: number) => {
return new Promise( resolve => setTimeout(resolve, ms) );
}
}

View File

@ -69,7 +69,7 @@ describe("SmartUiComponent", () => {
input: {
label: "Database",
dataFieldName: "database",
type: "enum",
type: "object",
choices: [
{ label: "Database 1", key: "db1", value: "database1" },
{ label: "Database 2", key: "db2", value: "database2" },

View File

@ -8,7 +8,7 @@ import { Text } from "office-ui-fabric-react/lib/Text";
import { InputType } from "../../Tables/Constants";
import { RadioSwitchComponent } from "../RadioSwitchComponent/RadioSwitchComponent";
import { Stack, IStackTokens } from "office-ui-fabric-react/lib/Stack";
import { Link, MessageBar, MessageBarType, PrimaryButton } from "office-ui-fabric-react";
import { Link, MessageBar, MessageBarType, PrimaryButton, Spinner, SpinnerSize } from "office-ui-fabric-react";
import * as InputUtils from "./InputUtils";
import "./SmartUiComponent.less";
@ -21,45 +21,45 @@ import "./SmartUiComponent.less";
* - a descriptor of the UX.
*/
export type InputTypeValue = "Number" | "String" | "Boolean" | "Object";
export type InputTypeValue = "number" | "string" | "boolean" | "object";
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export type EnumItem = { label: string; key: string; value: any };
export type ChoiceItem = { label: string; key: string; value: any };
export type InputType = Number | String | Boolean | EnumItem;
export type InputType = Number | String | Boolean | ChoiceItem;
interface BaseInput {
label: string;
label: (() => Promise<string>) | string;
dataFieldName: string;
type: InputTypeValue;
onChange?: (currentState: Map<string, InputType>, newValue: InputType) => Map<string, InputType>;
placeholder?: string;
placeholder?: (() => Promise<string>) | string;
}
/**
* For now, this only supports integers
*/
export interface NumberInput extends BaseInput {
min?: number;
max?: number;
step: number;
defaultValue: number;
min?: (() => Promise<number>) | number;
max?: (() => Promise<number>) | number
step: (() => Promise<number>) | number
defaultValue: (() => Promise<number>) | number
inputType: "spin" | "slider";
}
export interface BooleanInput extends BaseInput {
trueLabel: string;
falseLabel: string;
defaultValue: boolean;
trueLabel: (() => Promise<string>) | string;
falseLabel: (() => Promise<string>) | string;
defaultValue: (() => Promise<boolean>) | boolean;
}
export interface StringInput extends BaseInput {
defaultValue?: string;
defaultValue?: (() => Promise<string>) | string;
}
export interface EnumInput extends BaseInput {
choices: EnumItem[];
defaultKey: string;
export interface ChoiceInput extends BaseInput {
choices: (() => Promise<ChoiceItem[]>) | ChoiceItem[];
defaultKey: (() => Promise<string>) | string;
}
export interface Info {
@ -70,11 +70,11 @@ export interface Info {
};
}
export type AnyInput = NumberInput | BooleanInput | StringInput | EnumInput;
export type AnyInput = NumberInput | BooleanInput | StringInput | ChoiceInput;
export interface Node {
id: string;
info?: Info;
info?: (() => Promise<Info>) | Info;
input?: AnyInput;
children?: Node[];
}
@ -105,34 +105,98 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
constructor(props: SmartUiComponentProps) {
super(props);
this.state = {
currentValues: this.setDefaultValues(),
currentValues: undefined,
errors: new Map()
};
this.setDefaultValues()
}
private setDefaultValues = (): Map<string, InputType> => {
const defaults = new Map();
this.setDefaults(this.props.descriptor.root, defaults);
return defaults;
};
private setDefaultValues = async () : Promise<void> => {
const defaults = new Map<string, InputType>()
await this.setDefaults(this.props.descriptor.root, defaults)
this.setState({currentValues: defaults})
}
private setDefaults = (currentNode: Node, defaults: Map<string, InputType>) => {
if (currentNode.input?.dataFieldName) {
defaults.set(currentNode.input.dataFieldName, this.getDefault(currentNode.input));
private setDefaults = async (currentNode: Node, defaults: Map<string, InputType>) : Promise<void> => {
if (currentNode.info && currentNode.info instanceof Function) {
currentNode.info = await (currentNode.info as Function)()
}
currentNode.children?.map((child: Node) => this.setDefaults(child, defaults));
if (currentNode.input) {
currentNode.input = await this.getModifiedInput(currentNode.input)
defaults.set(currentNode.input.dataFieldName, this.getDefaultValue(currentNode.input));
}
await Promise.all(currentNode.children?.map(async (child: Node) => await this.setDefaults(child, defaults)));
};
private getDefault = (input: AnyInput): InputType => {
private getModifiedInput = async (input: AnyInput): Promise<AnyInput> => {
if (input.label instanceof Function) {
input.label = await (input.label as Function)()
}
if (input.placeholder instanceof Function) {
input.placeholder = await (input.placeholder as Function)()
}
switch (input.type) {
case "String":
return (input as StringInput).defaultValue;
case "Number":
return (input as NumberInput).defaultValue;
case "Boolean":
return (input as BooleanInput).defaultValue;
case "string":
const stringInput = input as StringInput
if (stringInput.defaultValue instanceof Function) {
stringInput.defaultValue = await (stringInput.defaultValue as Function)()
}
return stringInput;
case "number":
const numberInput = input as NumberInput
if (numberInput.defaultValue instanceof Function) {
numberInput.defaultValue = await (numberInput.defaultValue as Function)()
}
if (numberInput.min instanceof Function) {
numberInput.min = await (numberInput.min as Function)()
}
if (numberInput.max instanceof Function) {
numberInput.max = await (numberInput.max as Function)()
}
if (numberInput.step instanceof Function) {
numberInput.step = await (numberInput.step as Function)()
}
return numberInput;
case "boolean":
const booleanInput = input as BooleanInput
if (booleanInput.defaultValue instanceof Function) {
booleanInput.defaultValue = await (booleanInput.defaultValue as Function)()
}
if (booleanInput.trueLabel instanceof Function) {
booleanInput.trueLabel = await (booleanInput.trueLabel as Function)()
}
if (booleanInput.falseLabel instanceof Function) {
booleanInput.falseLabel = await (booleanInput.falseLabel as Function)()
}
return booleanInput;
default:
return (input as EnumInput).defaultKey;
const enumInput = input as ChoiceInput
if (enumInput.defaultKey instanceof Function) {
enumInput.defaultKey = await (enumInput.defaultKey as Function)()
}
if (enumInput.choices instanceof Function) {
enumInput.choices = await (enumInput.choices as Function)()
}
return enumInput
}
};
private getDefaultValue = (input: AnyInput): InputType => {
switch (input.type) {
case "string":
return (input as StringInput).defaultValue as string;
case "number":
return (input as NumberInput).defaultValue as number;
case "boolean":
return (input as BooleanInput).defaultValue as boolean;
default:
return (input as ChoiceInput).defaultKey as string;
}
};
@ -167,10 +231,10 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
<div>
<TextField
id={`${input.dataFieldName}-input`}
label={input.label}
label={input.label as string}
type="text"
value={input.defaultValue}
placeholder={input.placeholder}
defaultValue={input.defaultValue as string}
placeholder={input.placeholder as string}
onChange={(_, newValue) => this.onInputChange(input, newValue)}
styles={{
subComponentStyles: {
@ -233,17 +297,23 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
private renderNumberInput(input: NumberInput): JSX.Element {
const { label, min, max, defaultValue, dataFieldName, step } = input;
const props = { label, min, max, ariaLabel: label, step };
const props = {
label: label as string,
min: min as number,
max: max as number,
ariaLabel: label as string,
step: step as number
};
if (input.inputType === "spin") {
return (
<div>
<SpinButton
{...props}
defaultValue={defaultValue.toString()}
onValidate={newValue => this.onValidate(input, newValue, min, max)}
onIncrement={newValue => this.onIncrement(input, newValue, step, max)}
onDecrement={newValue => this.onDecrement(input, newValue, step, min)}
defaultValue={(defaultValue as number).toString()}
onValidate={newValue => this.onValidate(input, newValue, props.min, props.max)}
onIncrement={newValue => this.onIncrement(input, newValue, props.step, props.max)}
onDecrement={newValue => this.onDecrement(input, newValue, props.step, props.min)}
labelPosition={Position.top}
styles={{
label: {
@ -263,7 +333,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
// showValue={true}
// valueFormat={}
{...props}
defaultValue={defaultValue}
defaultValue={defaultValue as number}
onChange={newValue => this.onInputChange(input, newValue)}
styles={{
titleLabel: {
@ -291,12 +361,12 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
<RadioSwitchComponent
choices={[
{
label: input.falseLabel,
label: input.falseLabel as string,
key: "false",
onSelect: () => this.onInputChange(input, false)
},
{
label: input.trueLabel,
label: input.trueLabel as string,
key: "true",
onSelect: () => this.onInputChange(input, true)
}
@ -313,19 +383,19 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
);
}
private renderEnumInput(input: EnumInput): JSX.Element {
private renderEnumInput(input: ChoiceInput): JSX.Element {
const { label, defaultKey: defaultKey, dataFieldName, choices, placeholder } = input;
return (
<Dropdown
label={label}
label={label as string}
selectedKey={
this.state.currentValues.has(dataFieldName)
? (this.state.currentValues.get(dataFieldName) as string)
: defaultKey
: defaultKey as string
}
onChange={(_, item: IDropdownOption) => this.onInputChange(input, item.key.toString())}
placeholder={placeholder}
options={choices.map(c => ({
placeholder={placeholder as string}
options={(choices as ChoiceItem[]).map(c => ({
key: c.key,
text: c.value
}))}
@ -342,14 +412,14 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
private renderInput(input: AnyInput): JSX.Element {
switch (input.type) {
case "String":
case "string":
return this.renderStringInput(input as StringInput);
case "Number":
case "number":
return this.renderNumberInput(input as NumberInput);
case "Boolean":
case "boolean":
return this.renderBooleanInput(input as BooleanInput);
default:
return this.renderEnumInput(input as EnumInput);
return this.renderEnumInput(input as ChoiceInput);
}
}
@ -358,7 +428,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
return (
<Stack tokens={containerStackTokens} className="widgetRendererContainer">
{node.info && this.renderInfo(node.info)}
{node.info && this.renderInfo(node.info as Info)}
{node.input && this.renderInput(node.input)}
{node.children && node.children.map(child => <div key={child.id}>{this.renderNode(child)}</div>)}
</Stack>
@ -367,8 +437,8 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
render(): JSX.Element {
const containerStackTokens: IStackTokens = { childrenGap: 20 };
return (
this.state.currentValues && this.state.currentValues.size ?
<Stack tokens={containerStackTokens}>
{this.renderNode(this.props.descriptor.root)}
<PrimaryButton
@ -377,6 +447,8 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
onClick={async () => await this.props.descriptor.onSubmit(this.state.currentValues)}
/>
</Stack>
:
<Spinner size={SpinnerSize.large} />
);
}
}