123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- import classNames from 'classnames';
- import FormField from 'sentry/components/deprecatedforms/formField';
- import Tooltip from 'sentry/components/tooltip';
- import {IconQuestion} from 'sentry/icons';
- import {Choices} from 'sentry/types';
- import {defined} from 'sentry/utils';
- type Value = string | number | boolean;
- type Props = {
- choices: Choices;
- hideLabelDivider?: boolean;
- } & FormField['props'];
- type State = FormField['state'] & {
- values: Value[];
- };
- export default class MultipleCheckboxField extends FormField<Props, State> {
- onChange = (e: React.ChangeEvent<HTMLInputElement>, _value?: Value) => {
- const value = _value as Value; // Casting here to allow _value to be optional, which it has to be since it's overloaded.
- let allValues = this.state.values;
- if (e.target.checked) {
- if (allValues) {
- allValues = [...allValues, value];
- } else {
- allValues = [value];
- }
- } else {
- allValues = allValues.filter(v => v !== value);
- }
- this.setValues(allValues);
- };
- setValues(values: Value[]) {
- const form = (this.context || {}).form;
- this.setState(
- {
- values,
- },
- () => {
- const finalValue = this.coerceValue(this.state.values);
- this.props.onChange && this.props.onChange(finalValue);
- form && form.onFieldChange(this.props.name, finalValue);
- }
- );
- }
- render() {
- const {
- required,
- className,
- disabled,
- disabledReason,
- label,
- help,
- choices,
- hideLabelDivider,
- style,
- } = this.props;
- const {error} = this.state;
- const cx = classNames(className, 'control-group', {
- 'has-error': error,
- });
- // Hacky, but this isn't really a form label vs the checkbox labels, but
- // we want to treat it as one (i.e. for "required" indicator)
- const labelCx = classNames({
- required,
- });
- const shouldShowDisabledReason = disabled && disabledReason;
- return (
- <div style={style} className={cx}>
- <div className={labelCx}>
- <div className="controls">
- <label
- className="control-label"
- style={{
- display: 'block',
- marginBottom: !hideLabelDivider ? 10 : undefined,
- borderBottom: !hideLabelDivider ? '1px solid #f1eff3' : undefined,
- }}
- >
- {label}
- {shouldShowDisabledReason && (
- <Tooltip title={disabledReason}>
- <span className="disabled-indicator">
- <IconQuestion size="xs" />
- </span>
- </Tooltip>
- )}
- </label>
- {help && <p className="help-block">{help}</p>}
- {error && <p className="error">{error}</p>}
- </div>
- </div>
- <div className="control-list">
- {choices.map(([value, choiceLabel]) => (
- <label className="checkbox" key={value}>
- <input
- type="checkbox"
- value={value}
- onChange={e => this.onChange(e, value)}
- disabled={disabled}
- checked={
- defined(this.state.values) && this.state.values.indexOf(value) !== -1
- }
- />
- {choiceLabel}
- </label>
- ))}
- </div>
- </div>
- );
- }
- }
|