300 lines
8.6 KiB
TypeScript
300 lines
8.6 KiB
TypeScript
import React from "react";
|
|
import BaseWidget, { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
|
import { WidgetType } from "constants/WidgetConstants";
|
|
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
|
import {
|
|
ValidationResponse,
|
|
ValidationTypes,
|
|
} from "constants/WidgetValidation";
|
|
import { DerivedPropertiesMap } from "utils/WidgetFactory";
|
|
|
|
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
|
import CheckboxGroupComponent, { OptionProps } from "../component";
|
|
import { AutocompleteDataType } from "utils/autocomplete/TernServer";
|
|
|
|
function defaultSelectedValuesValidation(
|
|
value: unknown,
|
|
props: CheckboxGroupWidgetProps,
|
|
): ValidationResponse {
|
|
let isValid = true;
|
|
let values: string[] = [];
|
|
const messages: string[] = [];
|
|
const { options } = props;
|
|
|
|
const optionValues = options.map((option) => option.value);
|
|
|
|
if (typeof value === "string") {
|
|
try {
|
|
values = JSON.parse(value);
|
|
if (!Array.isArray(values)) {
|
|
throw new Error();
|
|
}
|
|
} catch {
|
|
values = value.length ? value.split(",") : [];
|
|
if (values.length > 0) {
|
|
values = values.map((_v: string) => _v.trim());
|
|
}
|
|
}
|
|
}
|
|
if (Array.isArray(value)) {
|
|
values = Array.from(new Set(value));
|
|
}
|
|
|
|
values.forEach((value, index) => {
|
|
if (!optionValues.includes(value)) {
|
|
isValid = false;
|
|
messages.push(`Mismatching value: ${value} at: ${index}`);
|
|
}
|
|
});
|
|
|
|
if (isValid) {
|
|
return {
|
|
isValid: true,
|
|
parsed: values,
|
|
};
|
|
}
|
|
|
|
return {
|
|
isValid: false,
|
|
parsed: values,
|
|
message: messages.join(" "),
|
|
};
|
|
}
|
|
|
|
class CheckboxGroupWidget extends BaseWidget<
|
|
CheckboxGroupWidgetProps,
|
|
WidgetState
|
|
> {
|
|
static getPropertyPaneConfig() {
|
|
return [
|
|
{
|
|
sectionName: "General",
|
|
children: [
|
|
{
|
|
helpText:
|
|
"Displays a list of options for a user to select. Values must be unique",
|
|
propertyName: "options",
|
|
label: "Options",
|
|
controlType: "OPTION_INPUT",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.ARRAY,
|
|
params: {
|
|
children: {
|
|
type: ValidationTypes.OBJECT,
|
|
params: {
|
|
allowedKeys: [
|
|
{
|
|
name: "label",
|
|
type: ValidationTypes.TEXT,
|
|
params: {
|
|
unique: true,
|
|
},
|
|
},
|
|
{
|
|
name: "value",
|
|
type: ValidationTypes.TEXT,
|
|
params: {
|
|
unique: true,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
evaluationSubstitutionType:
|
|
EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
|
},
|
|
{
|
|
helpText: "Selects values of the options checked by default",
|
|
propertyName: "defaultSelectedValues",
|
|
label: "Default Selected Values",
|
|
placeholderText: "Enter option values",
|
|
controlType: "INPUT_TEXT",
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.FUNCTION,
|
|
params: {
|
|
fn: defaultSelectedValuesValidation,
|
|
expected: {
|
|
type: "Value or Array of values",
|
|
example: `value1 | ['value1', 'value2']`,
|
|
autocompleteDataType: AutocompleteDataType.STRING,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
propertyName: "isInline",
|
|
label: "Inline",
|
|
controlType: "SWITCH",
|
|
helpText:
|
|
"Whether the checkbox buttons are to be displayed inline horizontally",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.BOOLEAN,
|
|
},
|
|
},
|
|
{
|
|
propertyName: "isRequired",
|
|
label: "Required",
|
|
helpText: "Makes input to the widget mandatory",
|
|
controlType: "SWITCH",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.BOOLEAN,
|
|
},
|
|
},
|
|
{
|
|
propertyName: "isVisible",
|
|
label: "Visible",
|
|
helpText: "Controls the visibility of the widget",
|
|
controlType: "SWITCH",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.BOOLEAN,
|
|
},
|
|
},
|
|
{
|
|
propertyName: "isDisabled",
|
|
label: "Disabled",
|
|
controlType: "SWITCH",
|
|
helpText: "Disables input to this widget",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: false,
|
|
validation: {
|
|
type: ValidationTypes.BOOLEAN,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
sectionName: "Actions",
|
|
children: [
|
|
{
|
|
helpText: "Triggers an action when the check state is changed",
|
|
propertyName: "onSelectionChange",
|
|
label: "onSelectionChange",
|
|
controlType: "ACTION_SELECTOR",
|
|
isJSConvertible: true,
|
|
isBindProperty: true,
|
|
isTriggerProperty: true,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
}
|
|
|
|
static getDefaultPropertiesMap(): Record<string, string> {
|
|
return {
|
|
selectedValues: "defaultSelectedValues",
|
|
};
|
|
}
|
|
|
|
static getMetaPropertiesMap(): Record<string, any> {
|
|
return {
|
|
selectedValues: undefined,
|
|
};
|
|
}
|
|
|
|
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
|
return {
|
|
isValid: `{{ this.isRequired ? !!this.selectedValues.length : true }}`,
|
|
};
|
|
}
|
|
|
|
componentDidUpdate(prevProps: CheckboxGroupWidgetProps) {
|
|
if (
|
|
Array.isArray(prevProps.options) &&
|
|
Array.isArray(this.props.options) &&
|
|
this.props.options.length !== prevProps.options.length
|
|
) {
|
|
const prevOptions = prevProps.options.map(
|
|
(prevOption) => prevOption.value,
|
|
);
|
|
const options = this.props.options.map((option) => option.value);
|
|
|
|
const diffOptions = prevOptions.filter(
|
|
(prevOption) => !options.includes(prevOption),
|
|
);
|
|
|
|
const selectedValues = this.props.selectedValues.filter(
|
|
(selectedValue: string) => !diffOptions.includes(selectedValue),
|
|
);
|
|
|
|
this.props.updateWidgetMetaProperty("selectedValues", selectedValues, {
|
|
triggerPropertyName: "onSelectionChange",
|
|
dynamicString: this.props.onSelectionChange,
|
|
event: {
|
|
type: EventType.ON_CHECK_CHANGE,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
getPageView() {
|
|
return (
|
|
<CheckboxGroupComponent
|
|
isDisabled={this.props.isDisabled}
|
|
isInline={this.props.isInline}
|
|
isRequired={this.props.isRequired}
|
|
isValid={this.props.isValid}
|
|
key={this.props.widgetId}
|
|
onChange={this.handleCheckboxChange}
|
|
options={this.props.options}
|
|
rowSpace={this.props.parentRowSpace}
|
|
selectedValues={this.props.selectedValues}
|
|
widgetId={this.props.widgetId}
|
|
/>
|
|
);
|
|
}
|
|
|
|
static getWidgetType(): WidgetType {
|
|
return "CHECKBOX_GROUP_WIDGET";
|
|
}
|
|
|
|
private handleCheckboxChange = (value: string) => {
|
|
return (event: React.FormEvent<HTMLElement>) => {
|
|
let { selectedValues } = this.props;
|
|
const isChecked = (event.target as HTMLInputElement).checked;
|
|
if (isChecked) {
|
|
selectedValues = [...selectedValues, value];
|
|
} else {
|
|
selectedValues = selectedValues.filter(
|
|
(item: string) => item !== value,
|
|
);
|
|
}
|
|
|
|
this.props.updateWidgetMetaProperty("selectedValues", selectedValues, {
|
|
triggerPropertyName: "onSelectionChange",
|
|
dynamicString: this.props.onSelectionChange,
|
|
event: {
|
|
type: EventType.ON_CHECKBOX_GROUP_SELECTION_CHANGE,
|
|
},
|
|
});
|
|
};
|
|
};
|
|
}
|
|
|
|
export interface CheckboxGroupWidgetProps extends WidgetProps {
|
|
options: OptionProps[];
|
|
isInline: boolean;
|
|
isRequired?: boolean;
|
|
isDisabled?: boolean;
|
|
isValid?: boolean;
|
|
onCheckChanged?: string;
|
|
}
|
|
|
|
export default CheckboxGroupWidget;
|