mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-02-23 20:48:11 +00:00
Added Recursive add
This commit is contained in:
parent
8cf160d818
commit
69b17f1a00
@ -45,7 +45,7 @@ import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readM
|
|||||||
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
||||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||||
import { isEmpty } from "underscore";
|
import { isEmpty } from "underscore";
|
||||||
import { SelfServeCmponent as SelfServeComponent } from "./SettingsSubComponents/SelfServe/SelfServe";
|
import { SelfServeCmponent as SelfServeComponent } from "./SettingsSubComponents/SelfServe/SelfServeComponent";
|
||||||
|
|
||||||
interface SettingsV2TabInfo {
|
interface SettingsV2TabInfo {
|
||||||
tab: SettingsV2TabTypes;
|
tab: SettingsV2TabTypes;
|
||||||
@ -903,8 +903,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
|
|
||||||
tabs.push({
|
tabs.push({
|
||||||
tab: SettingsV2TabTypes.SelfServe,
|
tab: SettingsV2TabTypes.SelfServe,
|
||||||
content: <SelfServeComponent propertyNames={['prop1', 'prop2']}/>
|
content: <SelfServeComponent propertyNames={["prop1", "prop2"]} />
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!hasDatabaseSharedThroughput(this.collection) && this.collection.offer()) {
|
if (!hasDatabaseSharedThroughput(this.collection) && this.collection.offer()) {
|
||||||
tabs.push({
|
tabs.push({
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
import { Descriptor, Info } from "../../../SmartUi/SmartUiComponent";
|
||||||
|
import { addPropertyToMap, DescriptorType, toSmartUiDescriptor } from "./SelfServeUtils";
|
||||||
|
|
||||||
|
interface SelfServeBaseCLass {
|
||||||
|
toSmartUiDescriptor: () => Descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelfServeClass() {
|
||||||
|
return <U extends SelfServeBaseCLass>(constructor: U) => {
|
||||||
|
constructor;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SmartUi = (): ClassDecorator => {
|
||||||
|
return (target: Function) => {
|
||||||
|
toSmartUiDescriptor(target.name, target);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ClassInfo = (info: Info): ClassDecorator => {
|
||||||
|
return (target: Function) => {
|
||||||
|
addPropertyToMap(target, "root", target.name, "info", info, DescriptorType.ClassDescriptor);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import { EnumItem, Info, InputTypeValue } from "../../../SmartUi/SmartUiComponent";
|
||||||
|
import { addPropertyToMap, DescriptorType } from "./SelfServeUtils";
|
||||||
|
|
||||||
|
const addToMap = (descriptorName: string, descriptorValue: any): PropertyDecorator => {
|
||||||
|
return (target, property) => {
|
||||||
|
const className = (target as Function).name;
|
||||||
|
if (!className) {
|
||||||
|
throw new Error("property descriptor applied to non static field!");
|
||||||
|
}
|
||||||
|
addPropertyToMap(
|
||||||
|
target,
|
||||||
|
property.toString(),
|
||||||
|
className,
|
||||||
|
descriptorName,
|
||||||
|
descriptorValue,
|
||||||
|
DescriptorType.PropertyDescriptor
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PropertyInfo = (info: Info): PropertyDecorator => {
|
||||||
|
return addToMap("info", info);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Placeholder = (placeholder: string): PropertyDecorator => {
|
||||||
|
return addToMap("placeholder", placeholder);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ParentOf = (children: string[]): PropertyDecorator => {
|
||||||
|
return addToMap("parentOf", children);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Type = (type: InputTypeValue): PropertyDecorator => {
|
||||||
|
return addToMap("type", type);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Label = (label: string): PropertyDecorator => {
|
||||||
|
return addToMap("label", label);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DataFieldName = (dataFieldName: string): PropertyDecorator => {
|
||||||
|
return addToMap("dataFieldName", dataFieldName);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Min = (min: number): PropertyDecorator => {
|
||||||
|
return addToMap("min", min);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Max = (max: number): PropertyDecorator => {
|
||||||
|
return addToMap("max", max);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Step = (step: number): PropertyDecorator => {
|
||||||
|
return addToMap("step", step);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultValue = (defaultValue: any): PropertyDecorator => {
|
||||||
|
return addToMap("defaultValue", defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TrueLabel = (trueLabel: string): PropertyDecorator => {
|
||||||
|
return addToMap("trueLabel", trueLabel);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FalseLabel = (falseLabel: string): PropertyDecorator => {
|
||||||
|
return addToMap("falseLabel", falseLabel);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Choices = (choices: EnumItem[]): PropertyDecorator => {
|
||||||
|
return addToMap("choices", choices);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultKey = (defaultKey: string): PropertyDecorator => {
|
||||||
|
return addToMap("defaultKey", defaultKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NumberInputType = (numberInputType: string): PropertyDecorator => {
|
||||||
|
return addToMap("inputType", numberInputType);
|
||||||
|
};
|
@ -1,87 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Descriptor, InputType, SmartUiComponent } from "../../../SmartUi/SmartUiComponent";
|
|
||||||
import { SqlX } from "./SqlX";
|
|
||||||
|
|
||||||
interface SelfServeComponentProps {
|
|
||||||
propertyNames: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SelfServeCmponent extends React.Component<SelfServeComponentProps> {
|
|
||||||
|
|
||||||
private properties: any = {}
|
|
||||||
|
|
||||||
constructor(props: SelfServeComponentProps) {
|
|
||||||
super(props)
|
|
||||||
let stringer = "{"
|
|
||||||
for (var i =0; i < props.propertyNames.length; i++) {
|
|
||||||
stringer += `"${props.propertyNames[i]}":null,`
|
|
||||||
}
|
|
||||||
stringer = stringer.substring(0, stringer.length-1)
|
|
||||||
console.log(stringer)
|
|
||||||
stringer += "}"
|
|
||||||
this.properties = JSON.parse(stringer)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private selfServeData: Descriptor = {
|
|
||||||
root: {
|
|
||||||
id: "root",
|
|
||||||
info: {
|
|
||||||
message: "Start at $24/mo per database",
|
|
||||||
link: {
|
|
||||||
href: "https://aka.ms/azure-cosmos-db-pricing",
|
|
||||||
text: "More Details"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
children: {
|
|
||||||
"instanceCount" : {
|
|
||||||
id: "instanceCount",
|
|
||||||
input: {
|
|
||||||
label: "Instance Count",
|
|
||||||
dataFieldName: "instanceCount",
|
|
||||||
type: "number",
|
|
||||||
min: 1,
|
|
||||||
max: 5,
|
|
||||||
step: 1,
|
|
||||||
defaultValue: 1,
|
|
||||||
inputType: "slider"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"instanceSize": {
|
|
||||||
id: "instanceSize",
|
|
||||||
input: {
|
|
||||||
label: "Instance Size",
|
|
||||||
dataFieldName: "instanceSize",
|
|
||||||
type: "enum",
|
|
||||||
choices: [
|
|
||||||
{ label: "1Core4Gb", key: "1Core4Gb", value: "1Core4Gb" },
|
|
||||||
{ label: "2Core8Gb", key: "2Core8Gb", value: "2Core8Gb" },
|
|
||||||
{ label: "4Core16Gb", key: "4Core16Gb", value: "4Core16Gb" }
|
|
||||||
],
|
|
||||||
defaultKey: "1Core4Gb"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private exampleCallbacks = (newValues: Map<string, InputType>): void => {
|
|
||||||
for (var i =0; i < this.props.propertyNames.length; i++) {
|
|
||||||
const prop = this.props.propertyNames[i]
|
|
||||||
const newVal = newValues.get(prop)
|
|
||||||
if (newVal) {
|
|
||||||
this.properties[`${prop}`] = newVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(this.properties)
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() : JSX.Element {
|
|
||||||
const data : Descriptor = {root: SqlX.toJson()}
|
|
||||||
//return <SmartUiComponent descriptor={this.selfServeData} onChange={this.exampleCallbacks} />
|
|
||||||
return <SmartUiComponent descriptor={data} onChange={this.exampleCallbacks} />
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,82 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Descriptor, InputType, SmartUiComponent } from "../../../SmartUi/SmartUiComponent";
|
||||||
|
import { SqlX } from "./SqlX";
|
||||||
|
|
||||||
|
interface SelfServeComponentProps {
|
||||||
|
propertyNames: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SelfServeCmponent extends React.Component<SelfServeComponentProps> {
|
||||||
|
private properties: any = {};
|
||||||
|
|
||||||
|
constructor(props: SelfServeComponentProps) {
|
||||||
|
super(props);
|
||||||
|
let stringer = "{";
|
||||||
|
for (var i = 0; i < props.propertyNames.length; i++) {
|
||||||
|
stringer += `"${props.propertyNames[i]}":null,`;
|
||||||
|
}
|
||||||
|
stringer = stringer.substring(0, stringer.length - 1);
|
||||||
|
console.log(stringer);
|
||||||
|
stringer += "}";
|
||||||
|
this.properties = JSON.parse(stringer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private selfServeData: Descriptor = {
|
||||||
|
root: {
|
||||||
|
id: "root",
|
||||||
|
info: {
|
||||||
|
message: "Start at $24/mo per database",
|
||||||
|
link: {
|
||||||
|
href: "https://aka.ms/azure-cosmos-db-pricing",
|
||||||
|
text: "More Details"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: "instanceCount",
|
||||||
|
input: {
|
||||||
|
label: "Instance Count",
|
||||||
|
dataFieldName: "instanceCount",
|
||||||
|
type: "number",
|
||||||
|
min: 1,
|
||||||
|
max: 5,
|
||||||
|
step: 1,
|
||||||
|
defaultValue: 1,
|
||||||
|
inputType: "slider"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "instanceSize",
|
||||||
|
input: {
|
||||||
|
label: "Instance Size",
|
||||||
|
dataFieldName: "instanceSize",
|
||||||
|
type: "enum",
|
||||||
|
choices: [
|
||||||
|
{ label: "1Core4Gb", key: "1Core4Gb", value: "1Core4Gb" },
|
||||||
|
{ label: "2Core8Gb", key: "2Core8Gb", value: "2Core8Gb" },
|
||||||
|
{ label: "4Core16Gb", key: "4Core16Gb", value: "4Core16Gb" }
|
||||||
|
],
|
||||||
|
defaultKey: "1Core4Gb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private exampleCallbacks = (newValues: Map<string, InputType>): void => {
|
||||||
|
for (var i = 0; i < this.props.propertyNames.length; i++) {
|
||||||
|
const prop = this.props.propertyNames[i];
|
||||||
|
const newVal = newValues.get(prop);
|
||||||
|
if (newVal) {
|
||||||
|
this.properties[`${prop}`] = newVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(this.properties);
|
||||||
|
};
|
||||||
|
|
||||||
|
public render(): JSX.Element {
|
||||||
|
//return <SmartUiComponent descriptor={this.selfServeData} onChange={this.exampleCallbacks} />
|
||||||
|
return <SmartUiComponent descriptor={SqlX.toSmartUiDescriptor()} onChange={this.exampleCallbacks} />;
|
||||||
|
}
|
||||||
|
}
|
@ -1,110 +0,0 @@
|
|||||||
|
|
||||||
import "reflect-metadata";
|
|
||||||
import { EnumItem, Info, InputTypeValue } from "../../../SmartUi/SmartUiComponent";
|
|
||||||
|
|
||||||
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 InfoBar = (metadataKey: string, info: Info) => {
|
|
||||||
return (target: any) => {
|
|
||||||
let context = Reflect.getMetadata(metadataKey, target)
|
|
||||||
if(!context) {
|
|
||||||
context = {id: "root", info: info, input: undefined, children: {} }
|
|
||||||
} else {
|
|
||||||
context.info = info
|
|
||||||
}
|
|
||||||
Reflect.defineMetadata(metadataKey, context, target)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Property = (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 modifyInputTypes = (metadataKey: string, fieldName: string, value: any) : PropertyDecorator => {
|
|
||||||
return (target, property) => {
|
|
||||||
let context = Reflect.getMetadata(metadataKey, target)
|
|
||||||
if(!context) {
|
|
||||||
throw new Error("Incorrect order")
|
|
||||||
}
|
|
||||||
context.children[property].input[fieldName] = value
|
|
||||||
//TODO: recurse to find correct child
|
|
||||||
console.log("props context:" + JSON.stringify(context))
|
|
||||||
Reflect.defineMetadata(metadataKey, context, target)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Type = (metadataKey: string, type: InputTypeValue): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "type", type)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Label = (metadataKey: string, label: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "label", label)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DataFieldName = (metadataKey: string, dataFieldName: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "dataFieldName", dataFieldName)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Min = (metadataKey: string, min: number): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "min", min)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Max = (metadataKey: string, max: number): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "max", max)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Step = (metadataKey: string, step: number): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "step", step)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DefaultValue = (metadataKey: string, defaultValue: any): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "defaultValue", defaultValue)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TrueLabel = (metadataKey: string, trueLabel: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "trueLabel", trueLabel)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FalseLabel = (metadataKey: string, falseLabel: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "falseLabel", falseLabel)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Choices = (metadataKey: string, choices: EnumItem[]): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "choices", choices)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DefaultKey = (metadataKey: string, defaultKey: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "defaultKey", defaultKey)
|
|
||||||
};
|
|
||||||
|
|
||||||
export const NumberInputType = (metadataKey: string, numberInputType: string): PropertyDecorator => {
|
|
||||||
return modifyInputTypes(metadataKey, "inputType", numberInputType)
|
|
||||||
};
|
|
@ -0,0 +1,211 @@
|
|||||||
|
import "reflect-metadata";
|
||||||
|
import {
|
||||||
|
EnumItem,
|
||||||
|
Node,
|
||||||
|
Info,
|
||||||
|
InputTypeValue,
|
||||||
|
Descriptor,
|
||||||
|
AnyInput,
|
||||||
|
NumberInput,
|
||||||
|
StringInput,
|
||||||
|
BooleanInput,
|
||||||
|
EnumInput
|
||||||
|
} from "../../../SmartUi/SmartUiComponent";
|
||||||
|
|
||||||
|
export interface CommonInputTypes {
|
||||||
|
id: string;
|
||||||
|
info?: Info;
|
||||||
|
parentOf?: string[];
|
||||||
|
type?: InputTypeValue;
|
||||||
|
label?: string;
|
||||||
|
placeholder?: string;
|
||||||
|
dataFieldName?: string;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
step?: number;
|
||||||
|
defaultValue?: any;
|
||||||
|
trueLabel?: string;
|
||||||
|
falseLabel?: string;
|
||||||
|
choices?: EnumItem[];
|
||||||
|
defaultKey?: string;
|
||||||
|
inputType?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DescriptorType {
|
||||||
|
ClassDescriptor,
|
||||||
|
PropertyDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
const setValue = <T extends keyof CommonInputTypes, K extends CommonInputTypes[T]>(
|
||||||
|
name: T,
|
||||||
|
value: K,
|
||||||
|
fieldObject: CommonInputTypes
|
||||||
|
): void => {
|
||||||
|
fieldObject[name] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getValue = <T extends keyof CommonInputTypes, K extends CommonInputTypes[T]>(
|
||||||
|
name: T,
|
||||||
|
fieldObject: CommonInputTypes
|
||||||
|
): K => {
|
||||||
|
return fieldObject[name];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addPropertyToMap = (
|
||||||
|
target: Object,
|
||||||
|
property: string,
|
||||||
|
metadataKey: string,
|
||||||
|
descriptorName: string,
|
||||||
|
descriptorValue: any,
|
||||||
|
descriptorType: DescriptorType
|
||||||
|
): void => {
|
||||||
|
const propertyKey = property.toString();
|
||||||
|
const descriptorKey = descriptorName.toString() as keyof CommonInputTypes;
|
||||||
|
let context = Reflect.getMetadata(metadataKey, target) as Map<String, CommonInputTypes>;
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
context = new Map<String, CommonInputTypes>();
|
||||||
|
}
|
||||||
|
|
||||||
|
let propertyObject = context.get(propertyKey);
|
||||||
|
if (!propertyObject) {
|
||||||
|
propertyObject = { id: propertyKey };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getValue(descriptorKey, propertyObject)) {
|
||||||
|
throw new Error("duplicate descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue(descriptorKey, descriptorValue, propertyObject);
|
||||||
|
context.set(propertyKey, propertyObject);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
const root = context.get("root");
|
||||||
|
context.delete("root");
|
||||||
|
|
||||||
|
let smartUiDescriptor = {
|
||||||
|
root: {
|
||||||
|
id: "root",
|
||||||
|
info: root.info,
|
||||||
|
children: []
|
||||||
|
} as Node
|
||||||
|
} as Descriptor;
|
||||||
|
|
||||||
|
while (context.size > 0) {
|
||||||
|
const key = context.keys().next().value;
|
||||||
|
addToDescriptor(context, smartUiDescriptor, smartUiDescriptor.root, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Reflect.defineMetadata(metadataKey, smartUiDescriptor, target);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToDescriptor = (
|
||||||
|
context: Map<String, CommonInputTypes>,
|
||||||
|
smartUiDescriptor: Descriptor,
|
||||||
|
root: Node,
|
||||||
|
key: String
|
||||||
|
): void => {
|
||||||
|
let value = context.get(key);
|
||||||
|
if (!value) {
|
||||||
|
// should already be added to root
|
||||||
|
value = getChildFromRoot(key, smartUiDescriptor);
|
||||||
|
if (!value) {
|
||||||
|
// 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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const childrenKeys = value.parentOf;
|
||||||
|
const element = {
|
||||||
|
id: value.id,
|
||||||
|
info: value.info,
|
||||||
|
input: getInput(value),
|
||||||
|
children: []
|
||||||
|
} as Node;
|
||||||
|
context.delete(key);
|
||||||
|
for (let childKey in childrenKeys) {
|
||||||
|
addToDescriptor(context, smartUiDescriptor, element, childrenKeys[childKey]);
|
||||||
|
}
|
||||||
|
root.children.push(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getChildFromRoot = (key: String, smartUiDescriptor: Descriptor): CommonInputTypes => {
|
||||||
|
let i = 0;
|
||||||
|
const children = smartUiDescriptor.root.children;
|
||||||
|
for (; i < children.length; i++) {
|
||||||
|
if (children[i].id === key) {
|
||||||
|
const value = children[i];
|
||||||
|
delete children[i];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInput = (value: CommonInputTypes): AnyInput => {
|
||||||
|
switch (value.type) {
|
||||||
|
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":
|
||||||
|
return value as StringInput;
|
||||||
|
case "boolean":
|
||||||
|
if (!value.trueLabel || !value.falseLabel || !value.defaultValue) {
|
||||||
|
throw new Error("truelabel, falselabel and defaultValue are needed for boolean type");
|
||||||
|
}
|
||||||
|
return value as BooleanInput;
|
||||||
|
case "enum":
|
||||||
|
if (!value.choices || !value.defaultKey) {
|
||||||
|
throw new Error("choices and defaultKey are needed for enum type");
|
||||||
|
}
|
||||||
|
return value as EnumInput;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown type");
|
||||||
|
}
|
||||||
|
};
|
@ -1,34 +1,58 @@
|
|||||||
import { DataFieldName, Label, Min, Max, Step, DefaultKey, DefaultValue, Property, Type, NumberInputType, Choices } from "./SelfServeTypes";
|
import {
|
||||||
import { EnumItem } from "../../../SmartUi/SmartUiComponent";
|
DataFieldName,
|
||||||
const SqlXRoot = 'SqlXRoot';
|
Label,
|
||||||
|
Min,
|
||||||
|
Max,
|
||||||
|
Step,
|
||||||
|
DefaultKey,
|
||||||
|
DefaultValue,
|
||||||
|
Type,
|
||||||
|
NumberInputType,
|
||||||
|
Choices,
|
||||||
|
ParentOf,
|
||||||
|
PropertyInfo
|
||||||
|
} from "./PropertyDescriptors";
|
||||||
|
import { Descriptor, EnumItem, Info } from "../../../SmartUi/SmartUiComponent";
|
||||||
|
import { SmartUi, ClassInfo, SelfServeClass } from "./ClassDescriptors";
|
||||||
|
|
||||||
|
@SmartUi()
|
||||||
|
@SelfServeClass()
|
||||||
|
@ClassInfo(SqlX.sqlXInfo)
|
||||||
export class SqlX {
|
export class SqlX {
|
||||||
@Label(SqlXRoot, "Instance Count")
|
@PropertyInfo(SqlX.instanceSizeInfo)
|
||||||
@DataFieldName(SqlXRoot, "instanceCount")
|
@Label("Instance Size")
|
||||||
@Min(SqlXRoot, 1)
|
@DataFieldName("instanceSize")
|
||||||
@Max(SqlXRoot, 5)
|
@Choices(SqlX.instanceSizeOptions)
|
||||||
@Step(SqlXRoot, 1)
|
@DefaultKey("1Core4Gb")
|
||||||
@DefaultValue(SqlXRoot, 1)
|
@Type("enum")
|
||||||
@NumberInputType(SqlXRoot, "slider")
|
static instanceSize: any;
|
||||||
@Type(SqlXRoot, "number")
|
|
||||||
@Property(SqlXRoot)
|
@Label("Instance Count")
|
||||||
|
@DataFieldName("instanceCount")
|
||||||
|
@Min(1)
|
||||||
|
@Max(5)
|
||||||
|
@Step(1)
|
||||||
|
@DefaultValue(1)
|
||||||
|
@NumberInputType("slider")
|
||||||
|
@Type("number")
|
||||||
|
@ParentOf(["instanceSize"])
|
||||||
static instanceCount: any;
|
static instanceCount: any;
|
||||||
|
|
||||||
@Label(SqlXRoot, "Instance Size")
|
static instanceSizeOptions: EnumItem[] = [
|
||||||
@DataFieldName(SqlXRoot, "instanceSize")
|
|
||||||
@Choices(SqlXRoot, SqlX.instanceTypeOptions)
|
|
||||||
@DefaultKey(SqlXRoot, "1Core4Gb")
|
|
||||||
@Type(SqlXRoot, "enum")
|
|
||||||
@Property(SqlXRoot)
|
|
||||||
static instanceType: any;
|
|
||||||
|
|
||||||
static instanceTypeOptions : EnumItem[] = [
|
|
||||||
{ label: "1Core4Gb", key: "1Core4Gb", value: "1Core4Gb" },
|
{ label: "1Core4Gb", key: "1Core4Gb", value: "1Core4Gb" },
|
||||||
{ label: "2Core8Gb", key: "2Core8Gb", value: "2Core8Gb" },
|
{ label: "2Core8Gb", key: "2Core8Gb", value: "2Core8Gb" },
|
||||||
{ label: "4Core16Gb", key: "4Core16Gb", value: "4Core16Gb" }
|
{ label: "4Core16Gb", key: "4Core16Gb", value: "4Core16Gb" }
|
||||||
]
|
];
|
||||||
|
|
||||||
public static toJson = () : any => {
|
static sqlXInfo: Info = {
|
||||||
return Reflect.getMetadata(SqlXRoot, SqlX)
|
message: "SqlX is a self serve class"
|
||||||
}
|
};
|
||||||
|
|
||||||
|
static instanceSizeInfo: Info = {
|
||||||
|
message: "instance size will be updated in the future"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static toSmartUiDescriptor = (): Descriptor => {
|
||||||
|
return Reflect.getMetadata(SqlX.name, SqlX) as Descriptor;
|
||||||
|
};
|
||||||
}
|
}
|
@ -13,8 +13,8 @@ describe("SmartUiComponent", () => {
|
|||||||
text: "More Details"
|
text: "More Details"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
children: {
|
children: [
|
||||||
"throughput": {
|
{
|
||||||
id: "throughput",
|
id: "throughput",
|
||||||
input: {
|
input: {
|
||||||
label: "Throughput (input)",
|
label: "Throughput (input)",
|
||||||
@ -27,7 +27,7 @@ describe("SmartUiComponent", () => {
|
|||||||
inputType: "spin"
|
inputType: "spin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"throughput2": {
|
{
|
||||||
id: "throughput2",
|
id: "throughput2",
|
||||||
input: {
|
input: {
|
||||||
label: "Throughput (Slider)",
|
label: "Throughput (Slider)",
|
||||||
@ -40,7 +40,7 @@ describe("SmartUiComponent", () => {
|
|||||||
inputType: "slider"
|
inputType: "slider"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"containerId": {
|
{
|
||||||
id: "containerId",
|
id: "containerId",
|
||||||
input: {
|
input: {
|
||||||
label: "Container id",
|
label: "Container id",
|
||||||
@ -48,7 +48,7 @@ describe("SmartUiComponent", () => {
|
|||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"analyticalStore": {
|
{
|
||||||
id: "analyticalStore",
|
id: "analyticalStore",
|
||||||
input: {
|
input: {
|
||||||
label: "Analytical Store",
|
label: "Analytical Store",
|
||||||
@ -59,7 +59,7 @@ describe("SmartUiComponent", () => {
|
|||||||
type: "boolean"
|
type: "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"database": {
|
{
|
||||||
id: "database",
|
id: "database",
|
||||||
input: {
|
input: {
|
||||||
label: "Database",
|
label: "Database",
|
||||||
@ -73,7 +73,7 @@ describe("SmartUiComponent", () => {
|
|||||||
defaultKey: "db2"
|
defaultKey: "db2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ export interface Node {
|
|||||||
id: string;
|
id: string;
|
||||||
info?: Info;
|
info?: Info;
|
||||||
input?: AnyInput;
|
input?: AnyInput;
|
||||||
children?: { [id: string]: Node} ;
|
children?: Node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Descriptor {
|
export interface Descriptor {
|
||||||
@ -113,9 +113,11 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
|||||||
return (
|
return (
|
||||||
<MessageBar>
|
<MessageBar>
|
||||||
{info.message}
|
{info.message}
|
||||||
|
{info.link && (
|
||||||
<Link href={info.link.href} target="_blank">
|
<Link href={info.link.href} target="_blank">
|
||||||
{info.link.text}
|
{info.link.text}
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -324,10 +326,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
|||||||
<Stack tokens={containerStackTokens} className="widgetRendererContainer">
|
<Stack tokens={containerStackTokens} className="widgetRendererContainer">
|
||||||
{node.info && this.renderInfo(node.info)}
|
{node.info && this.renderInfo(node.info)}
|
||||||
{node.input && this.renderInput(node.input)}
|
{node.input && this.renderInput(node.input)}
|
||||||
{node.children && Object.entries(node.children).map(([key, value]) => {
|
{node.children && node.children.map(child => <div key={child.id}>{this.renderNode(child)}</div>)}
|
||||||
return <div key={key}>{this.renderNode(value as Node)}</div>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user