2021-03-09 16:07:23 -08:00
|
|
|
import { ChoiceItem, Description, Info, InputType, NumberUiType, SmartUiInput, RefreshParams } from "./SelfServeTypes";
|
2021-01-26 09:44:14 -08:00
|
|
|
import { addPropertyToMap, DecoratorProperties, buildSmartUiDescriptor } from "./SelfServeUtils";
|
2021-01-19 22:42:45 -08:00
|
|
|
|
|
|
|
type ValueOf<T> = T[keyof T];
|
|
|
|
interface Decorator {
|
2021-01-26 09:44:14 -08:00
|
|
|
name: keyof DecoratorProperties;
|
|
|
|
value: ValueOf<DecoratorProperties>;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
interface InputOptionsBase {
|
2021-01-28 11:17:02 -08:00
|
|
|
labelTKey: string;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface NumberInputOptions extends InputOptionsBase {
|
|
|
|
min: (() => Promise<number>) | number;
|
|
|
|
max: (() => Promise<number>) | number;
|
|
|
|
step: (() => Promise<number>) | number;
|
2021-01-26 09:44:14 -08:00
|
|
|
uiType: NumberUiType;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface StringInputOptions extends InputOptionsBase {
|
2021-01-28 11:17:02 -08:00
|
|
|
placeholderTKey?: (() => Promise<string>) | string;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface BooleanInputOptions extends InputOptionsBase {
|
2021-01-28 11:17:02 -08:00
|
|
|
trueLabelTKey: (() => Promise<string>) | string;
|
|
|
|
falseLabelTKey: (() => Promise<string>) | string;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface ChoiceInputOptions extends InputOptionsBase {
|
|
|
|
choices: (() => Promise<ChoiceItem[]>) | ChoiceItem[];
|
2021-01-28 11:17:02 -08:00
|
|
|
placeholderTKey?: (() => Promise<string>) | string;
|
2021-01-26 09:44:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface DescriptionDisplayOptions {
|
2021-03-09 16:07:23 -08:00
|
|
|
labelTKey?: string;
|
2021-01-26 09:44:14 -08:00
|
|
|
description?: (() => Promise<Description>) | Description;
|
2021-03-09 16:07:23 -08:00
|
|
|
isDynamicDescription?: boolean;
|
2021-01-19 22:42:45 -08:00
|
|
|
}
|
|
|
|
|
2021-01-26 09:44:14 -08:00
|
|
|
type InputOptions =
|
|
|
|
| NumberInputOptions
|
|
|
|
| StringInputOptions
|
|
|
|
| BooleanInputOptions
|
|
|
|
| ChoiceInputOptions
|
|
|
|
| DescriptionDisplayOptions;
|
2021-01-19 22:42:45 -08:00
|
|
|
|
|
|
|
const isNumberInputOptions = (inputOptions: InputOptions): inputOptions is NumberInputOptions => {
|
|
|
|
return "min" in inputOptions;
|
|
|
|
};
|
|
|
|
|
|
|
|
const isBooleanInputOptions = (inputOptions: InputOptions): inputOptions is BooleanInputOptions => {
|
2021-01-28 11:17:02 -08:00
|
|
|
return "trueLabelTKey" in inputOptions;
|
2021-01-19 22:42:45 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
const isChoiceInputOptions = (inputOptions: InputOptions): inputOptions is ChoiceInputOptions => {
|
|
|
|
return "choices" in inputOptions;
|
|
|
|
};
|
|
|
|
|
2021-01-26 09:44:14 -08:00
|
|
|
const isDescriptionDisplayOptions = (inputOptions: InputOptions): inputOptions is DescriptionDisplayOptions => {
|
2021-03-09 16:07:23 -08:00
|
|
|
return "description" in inputOptions || "isDynamicDescription" in inputOptions;
|
2021-01-26 09:44:14 -08:00
|
|
|
};
|
|
|
|
|
2021-01-19 22:42:45 -08:00
|
|
|
const addToMap = (...decorators: Decorator[]): PropertyDecorator => {
|
|
|
|
return (target, property) => {
|
|
|
|
let className = target.constructor.name;
|
|
|
|
const propertyName = property.toString();
|
|
|
|
if (className === "Function") {
|
|
|
|
//eslint-disable-next-line @typescript-eslint/ban-types
|
|
|
|
className = (target as Function).name;
|
|
|
|
throw new Error(`Property '${propertyName}' in class '${className}'should be not be static.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const propertyType = (Reflect.getMetadata("design:type", target, property)?.name as string)?.toLowerCase();
|
|
|
|
addPropertyToMap(target, propertyName, className, "type", propertyType);
|
|
|
|
addPropertyToMap(target, propertyName, className, "dataFieldName", propertyName);
|
|
|
|
|
|
|
|
decorators.map((decorator: Decorator) =>
|
|
|
|
addPropertyToMap(target, propertyName, className, decorator.name, decorator.value)
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export const OnChange = (
|
2021-03-09 16:07:23 -08:00
|
|
|
onChange: (
|
|
|
|
newValue: InputType,
|
|
|
|
currentState: Map<string, SmartUiInput>,
|
|
|
|
baselineValues: ReadonlyMap<string, SmartUiInput>
|
|
|
|
) => Map<string, SmartUiInput>
|
2021-01-19 22:42:45 -08:00
|
|
|
): PropertyDecorator => {
|
|
|
|
return addToMap({ name: "onChange", value: onChange });
|
|
|
|
};
|
|
|
|
|
|
|
|
export const PropertyInfo = (info: (() => Promise<Info>) | Info): PropertyDecorator => {
|
|
|
|
return addToMap({ name: "info", value: info });
|
|
|
|
};
|
|
|
|
|
|
|
|
export const Values = (inputOptions: InputOptions): PropertyDecorator => {
|
|
|
|
if (isNumberInputOptions(inputOptions)) {
|
|
|
|
return addToMap(
|
2021-01-28 11:17:02 -08:00
|
|
|
{ name: "labelTKey", value: inputOptions.labelTKey },
|
2021-01-19 22:42:45 -08:00
|
|
|
{ name: "min", value: inputOptions.min },
|
|
|
|
{ name: "max", value: inputOptions.max },
|
|
|
|
{ name: "step", value: inputOptions.step },
|
|
|
|
{ name: "uiType", value: inputOptions.uiType }
|
|
|
|
);
|
|
|
|
} else if (isBooleanInputOptions(inputOptions)) {
|
|
|
|
return addToMap(
|
2021-01-28 11:17:02 -08:00
|
|
|
{ name: "labelTKey", value: inputOptions.labelTKey },
|
|
|
|
{ name: "trueLabelTKey", value: inputOptions.trueLabelTKey },
|
|
|
|
{ name: "falseLabelTKey", value: inputOptions.falseLabelTKey }
|
2021-01-19 22:42:45 -08:00
|
|
|
);
|
|
|
|
} else if (isChoiceInputOptions(inputOptions)) {
|
2021-01-26 09:44:14 -08:00
|
|
|
return addToMap(
|
2021-01-28 11:17:02 -08:00
|
|
|
{ name: "labelTKey", value: inputOptions.labelTKey },
|
|
|
|
{ name: "placeholderTKey", value: inputOptions.placeholderTKey },
|
2021-01-26 09:44:14 -08:00
|
|
|
{ name: "choices", value: inputOptions.choices }
|
|
|
|
);
|
|
|
|
} else if (isDescriptionDisplayOptions(inputOptions)) {
|
2021-03-09 16:07:23 -08:00
|
|
|
return addToMap(
|
|
|
|
{ name: "labelTKey", value: inputOptions.labelTKey },
|
|
|
|
{ name: "description", value: inputOptions.description },
|
|
|
|
{ name: "isDynamicDescription", value: inputOptions.isDynamicDescription }
|
|
|
|
);
|
2021-01-19 22:42:45 -08:00
|
|
|
} else {
|
|
|
|
return addToMap(
|
2021-01-28 11:17:02 -08:00
|
|
|
{ name: "labelTKey", value: inputOptions.labelTKey },
|
|
|
|
{ name: "placeholderTKey", value: inputOptions.placeholderTKey }
|
2021-01-19 22:42:45 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
2021-01-26 09:44:14 -08:00
|
|
|
|
|
|
|
export const IsDisplayable = (): ClassDecorator => {
|
|
|
|
return (target) => {
|
|
|
|
buildSmartUiDescriptor(target.name, target.prototype);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-03-09 16:07:23 -08:00
|
|
|
export const RefreshOptions = (refreshParams: RefreshParams): ClassDecorator => {
|
2021-01-26 09:44:14 -08:00
|
|
|
return (target) => {
|
2021-03-09 16:07:23 -08:00
|
|
|
addPropertyToMap(target.prototype, "root", target.name, "refreshParams", refreshParams);
|
2021-01-26 09:44:14 -08:00
|
|
|
};
|
|
|
|
};
|