17573: Adds redux-form controlled multi-checkbox selection component.
[arvados-workbench2.git] / src / components / checkbox-field / checkbox-field.tsx
index b8f18e7fdc99520b977a12b38b6a8e3a003e3e8b..bfa3714ae95a31bf78a9815f04a9673463f17bc2 100644 (file)
@@ -2,26 +2,66 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import * as React from 'react';
+import React from 'react';
 import { WrappedFieldProps } from 'redux-form';
-import { ArvadosTheme } from '~/common/custom-theme';
-import { FormControlLabel, Checkbox, StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core';
+import {
+    FormControlLabel,
+    Checkbox,
+    FormControl,
+    FormGroup,
+    FormLabel,
+    FormHelperText
+} from '@material-ui/core';
 
-type CssRules = 'checkboxField';
-
-const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
-    checkboxField: {
-        
-    }
-});
-
-export const CheckboxField = withStyles(styles)((props: WrappedFieldProps & WithStyles<CssRules> & { label?: string }) =>
+export const CheckboxField = (props: WrappedFieldProps & { label?: string }) =>
     <FormControlLabel
         control={
             <Checkbox
                 checked={props.input.value}
                 onChange={props.input.onChange}
+                disabled={props.meta.submitting}
                 color="primary" />
         }
-        label={props.label} 
-    />);
\ No newline at end of file
+        label={props.label}
+    />;
+
+type MultiCheckboxFieldProps = {
+    items: string[];
+    label?: string;
+    minSelection?: number;
+    maxSelection?: number;
+    helperText?: string;
+    rowLayout?: boolean;
+}
+
+export const MultiCheckboxField = (props: WrappedFieldProps & MultiCheckboxFieldProps) => {
+    const isValid = (items: string[]) => (items.length >= (props.minSelection || 0)) &&
+        (items.length <= (props.maxSelection || items.length));
+    return <FormControl error={!isValid(props.input.value)}>
+        <FormLabel component='label'>{props.label}</FormLabel>
+        <FormGroup row={props.rowLayout}>
+        { props.items.map((item, idx) =>
+            <FormControlLabel
+                control={
+                    <Checkbox
+                        key={idx}
+                        name={`${props.input.name}[${idx}]`}
+                        value={item}
+                        checked={props.input.value.indexOf(item) !== -1}
+                        onChange={e => {
+                            const newValue = [...props.input.value];
+                            if (e.target.checked) {
+                                newValue.push(item);
+                            } else {
+                                newValue.splice(newValue.indexOf(item), 1);
+                            }
+                            if (!isValid(newValue)) { return; }
+                            return props.input.onChange(newValue);
+                        }}
+                        disabled={props.meta.submitting}
+                        color="primary" />
+                }
+                label={item} />) }
+        </FormGroup>
+        <FormHelperText>{props.helperText}</FormHelperText>
+    </FormControl> };
\ No newline at end of file