in web-console/src/views/explore-view/components/control-pane/control-pane.tsx [81:348]
function renderOptionsPropInput(
parameter: ParameterDefinition,
value: any,
onValueChange: (value: any) => void,
): {
element: JSX.Element;
onDropColumn?: (column: Column) => void;
onDropMeasure?: (measure: Measure) => void;
} {
const required = evaluateFunctor(parameter.required, parameterValues, querySource, where);
switch (parameter.type) {
case 'boolean': {
return {
element: (
<SegmentedControl
value={String(value)}
onValueChange={v => {
onValueChange(v === 'true');
}}
options={[
{ value: 'false', label: 'False' },
{ value: 'true', label: 'True' },
]}
small
/>
),
};
}
case 'number':
return {
element: (
<FancyNumericInput
value={value}
onValueChange={onValueChange}
placeholder={parameter.placeholder}
fill
min={parameter.min}
max={parameter.max}
/>
),
};
case 'string':
return {
element: (
<InputGroup
value={(value as string) || ''}
onChange={e => onValueChange(e.target.value)}
placeholder={parameter.placeholder}
fill
/>
),
};
case 'option': {
const controlOptions =
evaluateFunctor(parameter.options, parameterValues, querySource, where) || [];
const selectedOption: OptionValue | undefined = controlOptions.find(o => o === value);
return {
element: (
<Popover
fill
position="bottom-left"
minimal
content={
<Menu>
{controlOptions.map((o, i) => (
<MenuItem
key={i}
text={getModuleOptionLabel(o, parameter)}
labelElement={
o === selectedOption ? <Icon icon={IconNames.TICK} /> : undefined
}
onClick={() => onValueChange(o)}
/>
))}
</Menu>
}
>
<InputGroup
value={
typeof selectedOption === 'undefined'
? `Unknown option: ${value}`
: getModuleOptionLabel(selectedOption, parameter)
}
readOnly
fill
rightElement={<Button icon={IconNames.CARET_DOWN} minimal />}
/>
</Popover>
),
};
}
case 'options': {
const controlOptions =
evaluateFunctor(parameter.options, parameterValues, querySource, where) || [];
return {
element: (
<OptionsInput
options={controlOptions}
value={(value as OptionValue[]) || []}
onValueChange={onValueChange}
optionLabel={o => getModuleOptionLabel(o, parameter)}
allowDuplicates={parameter.allowDuplicates}
nonEmpty={parameter.nonEmpty}
/>
),
};
}
case 'expression': {
const handleSelectColumn = (c: Column) => {
onValueChange(ExpressionMeta.fromColumn(c));
};
return {
element: (
<NamedExpressionsInput<ExpressionMeta>
allowReordering
values={value ? [value] : []}
onValuesChange={vs => onValueChange(vs[0])}
singleton
nonEmpty={required}
itemMenu={(initExpression, onClose) => (
<ExpressionMenu
columns={columns}
initExpression={initExpression}
onSelectExpression={onValueChange}
onClose={onClose}
onAddToSourceQueryAsColumn={onAddToSourceQueryAsColumn}
/>
)}
/>
),
onDropColumn: handleSelectColumn,
};
}
case 'expressions': {
const disabledColumnNames = parameter.allowDuplicates
? []
: filterMap(value as ExpressionMeta[], ({ expression }) =>
expression instanceof SqlColumn ? expression.getName() : undefined,
);
return {
element: (
<NamedExpressionsInput<ExpressionMeta>
allowReordering
values={value as ExpressionMeta[]}
onValuesChange={onValueChange}
nonEmpty={parameter.nonEmpty}
itemMenu={(initExpression, onClose) => (
<ExpressionMenu
columns={columns}
initExpression={initExpression}
onSelectExpression={c => onValueChange(changeOrAdd(value, initExpression, c))}
disabledColumnNames={disabledColumnNames}
onClose={onClose}
onAddToSourceQueryAsColumn={onAddToSourceQueryAsColumn}
/>
)}
/>
),
onDropColumn: (column: Column) => {
const columnName = column.name;
if (
!parameter.allowDuplicates &&
value.find((v: ExpressionMeta) => v.name === columnName)
) {
AppToaster.show({
intent: Intent.WARNING,
message: (
<>
<Tag minimal>{columnName}</Tag> already selected
</>
),
});
return;
}
onValueChange(value.concat(ExpressionMeta.fromColumn(column)));
},
};
}
case 'measure': {
return {
element: (
<NamedExpressionsInput<Measure>
values={value ? [value] : []}
onValuesChange={vs => onValueChange(vs[0])}
singleton
nonEmpty={required}
itemMenu={(initMeasure, onClose) => (
<MeasureMenu
columns={columns}
measures={measures}
initMeasure={initMeasure}
onSelectMeasure={onValueChange}
onClose={onClose}
onAddToSourceQueryAsMeasure={onAddToSourceQueryAsMeasure}
/>
)}
/>
),
onDropColumn: column => {
const candidateMeasures = Measure.getPossibleMeasuresForColumn(column).filter(
p => !value || value.name !== p.name,
);
if (!candidateMeasures.length) return;
onValueChange(candidateMeasures[0]);
},
onDropMeasure: onValueChange,
};
}
case 'measures': {
const disabledMeasureNames = parameter.allowDuplicates
? []
: filterMap(value as Measure[], measure => measure.getAggregateMeasureName());
return {
element: (
<NamedExpressionsInput<Measure>
values={value}
onValuesChange={onValueChange}
allowReordering
nonEmpty={parameter.nonEmpty}
itemMenu={(initMeasure, onClose) => (
<MeasureMenu
columns={columns}
measures={measures}
initMeasure={initMeasure}
disabledMeasureNames={disabledMeasureNames}
onSelectMeasure={m => onValueChange(changeOrAdd(value, initMeasure, m))}
onClose={onClose}
onAddToSourceQueryAsMeasure={onAddToSourceQueryAsMeasure}
/>
)}
/>
),
onDropColumn: column => {
const candidateMeasures = Measure.getPossibleMeasuresForColumn(column).filter(
p => !value.some((v: Measure) => v.name === p.name),
);
if (!candidateMeasures.length) return;
onValueChange(value.concat(candidateMeasures[0]));
},
onDropMeasure: measure => {
onValueChange(value.concat(measure));
},
};
}
default:
return {
element: (
<Button
icon={IconNames.ERROR}
text={`Type not supported: ${(parameter as { type: string }).type}`}
disabled
fill
/>
),
};
}
}