19783: Add flexbox wrappers to allow dialog content to shrink on small window height 19783-picking-tweak
authorStephen Smith <stephen@curii.com>
Thu, 15 Dec 2022 18:22:32 +0000 (13:22 -0500)
committerStephen Smith <stephen@curii.com>
Thu, 15 Dec 2022 18:22:32 +0000 (13:22 -0500)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

12 files changed:
src/components/file-upload/file-upload.tsx
src/components/form-dialog/form-dialog.tsx
src/views-components/dialog-copy/dialog-collection-partial-copy.tsx
src/views-components/dialog-copy/dialog-copy.tsx
src/views-components/dialog-copy/dialog-partial-copy-to-collection.tsx
src/views-components/file-uploader/file-uploader.tsx
src/views-components/projects-tree-picker/tree-picker-field.tsx
src/views/run-process-panel/inputs/directory-array-input.tsx
src/views/run-process-panel/inputs/directory-input.tsx
src/views/run-process-panel/inputs/file-array-input.tsx
src/views/run-process-panel/inputs/file-input.tsx
src/views/run-process-panel/inputs/project-input.tsx

index 54d5b5db2b9513a34579d1d5465a89587c3fb8eb..e6c15144522fa8467ed43296d312a507cf4eba00 100644 (file)
@@ -34,7 +34,8 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
         width: "100%",
         height: "200px",
         position: "relative",
-        border: "1px solid rgba(0, 0, 0, 0.42)"
+        border: "1px solid rgba(0, 0, 0, 0.42)",
+        boxSizing: 'border-box',
     },
     dropzoneBorder: {
         content: "",
index 0fc799dee92b62eb0ab58a6ce100403dc7477193..b50504a6c0b7a7ef4bd8da5bb330a73a18e0406c 100644 (file)
@@ -8,7 +8,7 @@ import { Dialog, DialogActions, DialogContent, DialogTitle } from '@material-ui/
 import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
 import { WithDialogProps } from 'store/dialog/with-dialog';
 
-type CssRules = "button" | "lastButton" | "formContainer" | "dialogTitle" | "progressIndicator" | "dialogActions";
+type CssRules = "button" | "lastButton" | "form" | "formContainer" | "dialogTitle" | "progressIndicator" | "dialogActions";
 
 const styles: StyleRulesCallback<CssRules> = theme => ({
     button: {
@@ -18,6 +18,12 @@ const styles: StyleRulesCallback<CssRules> = theme => ({
         marginLeft: theme.spacing.unit,
         marginRight: "0",
     },
+    form: {
+        display: 'flex',
+        overflowY: 'auto',
+        flexDirection: 'column',
+        flex: '0 1 auto',
+    },
     formContainer: {
         display: "flex",
         flexDirection: "column",
@@ -57,7 +63,7 @@ export const FormDialog = withStyles(styles)((props: DialogProjectProps) =>
         disableEscapeKeyDown={props.submitting}
         fullWidth
         maxWidth='md'>
-        <form data-cy='form-dialog'>
+        <form data-cy='form-dialog' className={props.classes.form}>
             <DialogTitle className={props.classes.dialogTitle}>
                 {props.dialogTitle}
             </DialogTitle>
index 7a3c5fddd1255c1c3f92c30d5ce137fdf2460f9e..3c584e4f51452381d56296e753ad182123af82f2 100644 (file)
@@ -24,8 +24,8 @@ export const DialogCollectionPartialCopy = (props: DialogCollectionPartialCopyPr
 export const CollectionPartialCopyFields = memoize(
     (pickerId: string) =>
         () =>
-            <div>
+            <>
                 <CollectionNameField />
                 <CollectionDescriptionField />
                 <CollectionProjectPickerField {...{ pickerId }} />
-            </div>);
+            </>);
index 5605e6caa866c266990caa9722ac94be96004aef..a3e301195493be96d99b9b0c3c96648b2b6828e8 100644 (file)
@@ -25,7 +25,7 @@ export const DialogCopy = (props: CopyFormDialogProps & PickerIdProp) =>
 
 const CopyDialogFields = memoize((pickerId: string) =>
     () =>
-        <span>
+        <>
             <Field
                 name='name'
                 component={TextField as any}
@@ -36,4 +36,4 @@ const CopyDialogFields = memoize((pickerId: string) =>
                 component={ProjectTreePickerField}
                 validate={COPY_FILE_VALIDATION}
                 pickerId={pickerId}/>
-        </span>);
+        </>);
index a79ed0bcce76250490232ec0f94bb327655d6669..4e9dde6a12bc2ef56e1fafa1cf34d73329e660d8 100644 (file)
@@ -24,6 +24,6 @@ export const DialogCollectionPartialCopyToSelectedCollection = (props: DialogCol
 export const CollectionPartialCopyFields = memoize(
     (pickerId: string) =>
         () =>
-            <div>
+            <>
                 <CollectionPickerField {...{ pickerId }}/>
-            </div>);
+            </>);
index cde286c450c4764be139b288c65ab3ab55f9d4e2..be59261722377a7001b59c85bbac3d72dbf1536a 100644 (file)
@@ -36,7 +36,7 @@ const mapDispatchToProps = (dispatch: Dispatch, { onDrop }: FileUploaderProps):
 export const FileUploader = connect(mapStateToProps, mapDispatchToProps)(FileUpload);
 
 export const FileUploaderField = (props: WrappedFieldProps & { label?: string }) =>
-    <div>
+    <>
         <Typography variant='caption'>{props.label}</Typography>
         <FileUploader disabled={false} onDrop={props.input.onChange} />
-    </div>;
+    </>;
index d6ebb8ec0754edaac0b7d7c4c902be1c86326f76..357058c54bf1c1d6564044b8159b2f47d2cc3282 100644 (file)
@@ -11,15 +11,17 @@ import { ProjectsTreePickerItem } from 'store/tree-picker/tree-picker-middleware
 import { PickerIdProp } from 'store/tree-picker/picker-id';
 
 export const ProjectTreePickerField = (props: WrappedFieldProps & PickerIdProp) =>
-    <div style={{ height: '200px', display: 'flex', flexDirection: 'column' }}>
-        <ProjectsTreePicker
-            pickerId={props.pickerId}
-            toggleItemActive={handleChange(props)}
-            options={{ showOnlyOwned: false, showOnlyWritable: true }} />
-        {props.meta.dirty && props.meta.error &&
-            <Typography variant='caption' color='error'>
-                {props.meta.error}
-            </Typography>}
+    <div style={{ display: 'flex', minHeight: 0, flexDirection: 'column' }}>
+        <div style={{ flexBasis: '200px', flexShrink: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
+            <ProjectsTreePicker
+                pickerId={props.pickerId}
+                toggleItemActive={handleChange(props)}
+                options={{ showOnlyOwned: false, showOnlyWritable: true }} />
+            {props.meta.dirty && props.meta.error &&
+                <Typography variant='caption' color='error'>
+                    {props.meta.error}
+                </Typography>}
+        </div>
     </div>;
 
 const handleChange = (props: WrappedFieldProps) =>
@@ -27,14 +29,16 @@ const handleChange = (props: WrappedFieldProps) =>
         props.input.onChange(id);
 
 export const CollectionTreePickerField = (props: WrappedFieldProps & PickerIdProp) =>
-    <div style={{ height: '200px', display: 'flex', flexDirection: 'column' }}>
-        <ProjectsTreePicker
-            pickerId={props.pickerId}
-            toggleItemActive={handleChange(props)}
-            options={{ showOnlyOwned: false, showOnlyWritable: true }}
-            includeCollections />
-        {props.meta.dirty && props.meta.error &&
-            <Typography variant='caption' color='error'>
-                {props.meta.error}
-            </Typography>}
+    <div style={{ display: 'flex', minHeight: 0, flexDirection: 'column' }}>
+        <div style={{ flexBasis: '200px', flexShrink: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
+            <ProjectsTreePicker
+                pickerId={props.pickerId}
+                toggleItemActive={handleChange(props)}
+                options={{ showOnlyOwned: false, showOnlyWritable: true }}
+                includeCollections />
+            {props.meta.dirty && props.meta.error &&
+                <Typography variant='caption' color='error'>
+                    {props.meta.error}
+                </Typography>}
+        </div>
     </div>;
index 72dba752d6d9999656d9c1b743ee6d1163218743..e64dca0e49b9b8a8e55514267718108b82557662 100644 (file)
@@ -231,31 +231,17 @@ const DirectoryArrayInputComponent = connect(mapStateToProps)(
                 onBlur={this.props.input.onBlur}
                 disabled={this.props.commandInput.disabled} />
 
-        dialog = () =>
-            <Dialog
-                open={this.state.open}
-                onClose={this.closeDialog}
-                fullWidth
-                maxWidth='md' >
-                <DialogTitle>Choose collections</DialogTitle>
-                <DialogContent>
-                    <this.dialogContent />
-                </DialogContent>
-                <DialogActions>
-                    <Button onClick={this.closeDialog}>Cancel</Button>
-                    <Button
-                        data-cy='ok-button'
-                        variant='contained'
-                        color='primary'
-                        onClick={this.submit}>Ok</Button>
-                </DialogActions>
-            </Dialog>
-
         dialogContentStyles: StyleRulesCallback<DialogContentCssRules> = ({ spacing }) => ({
             root: {
                 display: 'flex',
                 flexDirection: 'column',
-                height: `${spacing.unit * 8}vh`,
+            },
+            pickerWrapper: {
+                display: 'flex',
+                flexDirection: 'column',
+                flexBasis: `${spacing.unit * 8}vh`,
+                flexShrink: 1,
+                minHeight: 0,
             },
             tree: {
                 flex: 3,
@@ -270,11 +256,33 @@ const DirectoryArrayInputComponent = connect(mapStateToProps)(
                 padding: `${spacing.unit}px 0`,
                 overflowX: 'hidden',
             },
-        })
+        });
+
+        dialog = withStyles(this.dialogContentStyles)(
+            ({ classes }: WithStyles<DialogContentCssRules>) =>
+                <Dialog
+                    open={this.state.open}
+                    onClose={this.closeDialog}
+                    fullWidth
+                    maxWidth='md' >
+                    <DialogTitle>Choose collections</DialogTitle>
+                    <DialogContent className={classes.root}>
+                        <this.dialogContent />
+                    </DialogContent>
+                    <DialogActions>
+                        <Button onClick={this.closeDialog}>Cancel</Button>
+                        <Button
+                            data-cy='ok-button'
+                            variant='contained'
+                            color='primary'
+                            onClick={this.submit}>Ok</Button>
+                    </DialogActions>
+                </Dialog>
+        );
 
         dialogContent = withStyles(this.dialogContentStyles)(
             ({ classes }: WithStyles<DialogContentCssRules>) =>
-                <div className={classes.root}>
+                <div className={classes.pickerWrapper}>
                     <div className={classes.tree}>
                         <ProjectsTreePicker
                             pickerId={this.props.commandInput.id}
@@ -298,4 +306,4 @@ const DirectoryArrayInputComponent = connect(mapStateToProps)(
 
     });
 
-type DialogContentCssRules = 'root' | 'tree' | 'divider' | 'chips';
+type DialogContentCssRules = 'root' | 'pickerWrapper' | 'tree' | 'divider' | 'chips';
index 1faf73818ab94c8252427297ff4f0495cbc35303..5348cc2b76ca93a4e24fc1d9474702bc327867e2 100644 (file)
@@ -27,7 +27,7 @@ export interface DirectoryInputProps {
     options?: { showOnlyOwned: boolean, showOnlyWritable: boolean };
 }
 
-type DialogContentCssRules = 'root';
+type DialogContentCssRules = 'root' | 'pickerWrapper';
 
 export const DirectoryInput = ({ input, options }: DirectoryInputProps) =>
     <Field
@@ -78,7 +78,7 @@ const DirectoryInputComponent = connect()(
         render() {
             return <>
                 {this.renderInput()}
-                {this.renderDialog()}
+                <this.dialog />
             </>;
         }
 
@@ -119,41 +119,43 @@ const DirectoryInputComponent = connect()(
 
         dialogContentStyles: StyleRulesCallback<DialogContentCssRules> = ({ spacing }) => ({
             root: {
-                height: `${spacing.unit * 8}vh`,
+                display: 'flex',
+                flexDirection: 'column',
+            },
+            pickerWrapper: {
+                flexBasis: `${spacing.unit * 8}vh`,
+                flexShrink: 1,
+                minHeight: 0,
             },
         });
 
-        renderDialog() {
-            return <Dialog
-                open={this.state.open}
-                onClose={this.closeDialog}
-                fullWidth
-                data-cy="choose-a-directory-dialog"
-                maxWidth='md'>
-                <DialogTitle>Choose a directory</DialogTitle>
-                <DialogContent>
-                    <this.dialogContent />
-                </DialogContent>
-                <DialogActions>
-                    <Button onClick={this.closeDialog}>Cancel</Button>
-                    <Button
-                        disabled={!this.state.directory}
-                        variant='contained'
-                        color='primary'
-                        onClick={this.submit}>Ok</Button>
-                </DialogActions>
-            </Dialog>;
-        }
-
-        dialogContent = withStyles(this.dialogContentStyles)(
+        dialog = withStyles(this.dialogContentStyles)(
             ({ classes }: WithStyles<DialogContentCssRules>) =>
-                <div className={classes.root}>
-                    <ProjectsTreePicker
-                        pickerId={this.props.commandInput.id}
-                        includeCollections
-                        options={this.props.options}
-                        toggleItemActive={this.setDirectory} />
-                </div>
+                <Dialog
+                    open={this.state.open}
+                    onClose={this.closeDialog}
+                    fullWidth
+                    data-cy="choose-a-directory-dialog"
+                    maxWidth='md'>
+                    <DialogTitle>Choose a directory</DialogTitle>
+                    <DialogContent className={classes.root}>
+                        <div className={classes.pickerWrapper}>
+                            <ProjectsTreePicker
+                                pickerId={this.props.commandInput.id}
+                                includeCollections
+                                options={this.props.options}
+                                toggleItemActive={this.setDirectory} />
+                        </div>
+                    </DialogContent>
+                    <DialogActions>
+                        <Button onClick={this.closeDialog}>Cancel</Button>
+                        <Button
+                            disabled={!this.state.directory}
+                            variant='contained'
+                            color='primary'
+                            onClick={this.submit}>Ok</Button>
+                    </DialogActions>
+                </Dialog>
         );
 
     });
index 712f6418df6f7c041e49b2726232f2b5fcbfcce5..0be8f19feda9e40fe2ab7aebffb497250ca3c688 100644 (file)
@@ -212,31 +212,17 @@ const FileArrayInputComponent = connect(mapStateToProps)(
                 onKeyPress={!this.props.commandInput.disabled ? this.openDialog : undefined}
                 onBlur={this.props.input.onBlur} />
 
-        dialog = () =>
-            <Dialog
-                open={this.state.open}
-                onClose={this.closeDialog}
-                fullWidth
-                maxWidth='md' >
-                <DialogTitle>Choose files</DialogTitle>
-                <DialogContent>
-                    <this.dialogContent />
-                </DialogContent>
-                <DialogActions>
-                    <Button onClick={this.closeDialog}>Cancel</Button>
-                    <Button
-                        data-cy='ok-button'
-                        variant='contained'
-                        color='primary'
-                        onClick={this.submit}>Ok</Button>
-                </DialogActions>
-            </Dialog>
-
         dialogContentStyles: StyleRulesCallback<DialogContentCssRules> = ({ spacing }) => ({
             root: {
                 display: 'flex',
                 flexDirection: 'column',
-                height: `${spacing.unit * 8}vh`,
+            },
+            pickerWrapper: {
+                display: 'flex',
+                flexDirection: 'column',
+                flexBasis: `${spacing.unit * 8}vh`,
+                flexShrink: 1,
+                minHeight: 0,
             },
             tree: {
                 flex: 3,
@@ -253,9 +239,32 @@ const FileArrayInputComponent = connect(mapStateToProps)(
             },
         })
 
+
+        dialog = withStyles(this.dialogContentStyles)(
+            ({ classes }: WithStyles<DialogContentCssRules>) =>
+                <Dialog
+                    open={this.state.open}
+                    onClose={this.closeDialog}
+                    fullWidth
+                    maxWidth='md' >
+                    <DialogTitle>Choose files</DialogTitle>
+                    <DialogContent className={classes.root}>
+                        <this.dialogContent />
+                    </DialogContent>
+                    <DialogActions>
+                        <Button onClick={this.closeDialog}>Cancel</Button>
+                        <Button
+                            data-cy='ok-button'
+                            variant='contained'
+                            color='primary'
+                            onClick={this.submit}>Ok</Button>
+                    </DialogActions>
+                </Dialog>
+        );
+
         dialogContent = withStyles(this.dialogContentStyles)(
             ({ classes }: WithStyles<DialogContentCssRules>) =>
-                <div className={classes.root}>
+                <div className={classes.pickerWrapper}>
                     <div className={classes.tree}>
                         <ProjectsTreePicker
                             pickerId={this.props.commandInput.id}
@@ -280,4 +289,4 @@ const FileArrayInputComponent = connect(mapStateToProps)(
 
     });
 
-type DialogContentCssRules = 'root' | 'tree' | 'divider' | 'chips';
+type DialogContentCssRules = 'root' | 'pickerWrapper' | 'tree' | 'divider' | 'chips';
index fd1440c358ce59fceb2fc49fb3bcc94134c8609f..218bf4189cbabebe6330089bb47f6fa23c8e8f3a 100644 (file)
@@ -26,7 +26,7 @@ export interface FileInputProps {
     options?: { showOnlyOwned: boolean, showOnlyWritable: boolean };
 }
 
-type DialogContentCssRules = 'root';
+type DialogContentCssRules = 'root' | 'pickerWrapper';
 
 export const FileInput = ({ input, options }: FileInputProps) =>
     <Field
@@ -76,7 +76,7 @@ const FileInputComponent = connect()(
         render() {
             return <>
                 {this.renderInput()}
-                {this.renderDialog()}
+                <this.dialog />
             </>;
         }
 
@@ -118,35 +118,42 @@ const FileInputComponent = connect()(
 
         dialogContentStyles: StyleRulesCallback<DialogContentCssRules> = ({ spacing }) => ({
             root: {
-                height: `${spacing.unit * 8}vh`,
+                display: 'flex',
+                flexDirection: 'column',
+            },
+            pickerWrapper: {
+                flexBasis: `${spacing.unit * 8}vh`,
+                flexShrink: 1,
+                minHeight: 0,
             },
         });
 
-        renderDialog() {
-            return <Dialog
-                open={this.state.open}
-                onClose={this.closeDialog}
-                fullWidth
-                data-cy="choose-a-file-dialog"
-                maxWidth='md'>
-                <DialogTitle>Choose a file</DialogTitle>
-                <DialogContent>
-                    <this.dialogContent />
-                </DialogContent>
-                <DialogActions>
-                    <Button onClick={this.closeDialog}>Cancel</Button>
-                    <Button
-                        disabled={!this.state.file}
-                        variant='contained'
-                        color='primary'
-                        onClick={this.submit}>Ok</Button>
-                </DialogActions>
-            </Dialog >;
-        }
+        dialog = withStyles(this.dialogContentStyles)(
+            ({ classes }: WithStyles<DialogContentCssRules>) =>
+                <Dialog
+                    open={this.state.open}
+                    onClose={this.closeDialog}
+                    fullWidth
+                    data-cy="choose-a-file-dialog"
+                    maxWidth='md'>
+                    <DialogTitle>Choose a file</DialogTitle>
+                    <DialogContent className={classes.root}>
+                        <this.dialogContent />
+                    </DialogContent>
+                    <DialogActions>
+                        <Button onClick={this.closeDialog}>Cancel</Button>
+                        <Button
+                            disabled={!this.state.file}
+                            variant='contained'
+                            color='primary'
+                            onClick={this.submit}>Ok</Button>
+                    </DialogActions>
+                </Dialog >
+        );
 
         dialogContent = withStyles(this.dialogContentStyles)(
             ({ classes }: WithStyles<DialogContentCssRules>) =>
-                <div className={classes.root}>
+                <div className={classes.pickerWrapper}>
                     <ProjectsTreePicker
                         pickerId={this.props.commandInput.id}
                         includeCollections
index 761cd1ed9badda265487dd6e9db25deeaa0697e0..ef6d08f40086dbeb4aa2d0596cdb412885c841f9 100644 (file)
@@ -28,7 +28,7 @@ export interface ProjectInputProps {
     options?: { showOnlyOwned: boolean, showOnlyWritable: boolean };
 }
 
-type DialogContentCssRules = 'root';
+type DialogContentCssRules = 'root' | 'pickerWrapper';
 
 export const ProjectInput = ({ input, options }: ProjectInputProps) =>
     <Field
@@ -70,7 +70,7 @@ export const ProjectInputComponent = connect(mapStateToProps)(
         render() {
             return <>
                 {this.renderInput()}
-                {this.renderDialog()}
+                <this.dialog />
             </>;
         }
 
@@ -114,40 +114,42 @@ export const ProjectInputComponent = connect(mapStateToProps)(
 
         dialogContentStyles: StyleRulesCallback<DialogContentCssRules> = ({ spacing }) => ({
             root: {
-                height: `${spacing.unit * 8}vh`,
+                display: 'flex',
+                flexDirection: 'column',
+            },
+            pickerWrapper: {
+                flexBasis: `${spacing.unit * 8}vh`,
+                flexShrink: 1,
+                minHeight: 0,
             },
         });
 
-        renderDialog() {
-            return this.state.open ? <Dialog
-                open={this.state.open}
-                onClose={this.closeDialog}
-                fullWidth
-                data-cy="choose-a-project-dialog"
-                maxWidth='md'>
-                <DialogTitle>Choose a project</DialogTitle>
-                <DialogContent>
-                    <this.dialogContent />
-                </DialogContent>
-                <DialogActions>
-                    <Button onClick={this.closeDialog}>Cancel</Button>
-                    <Button
-                        disabled={this.invalid()}
-                        variant='contained'
-                        color='primary'
-                        onClick={this.submit}>Ok</Button>
-                </DialogActions>
-            </Dialog> : null;
-        }
-
-        dialogContent = withStyles(this.dialogContentStyles)(
+        dialog = withStyles(this.dialogContentStyles)(
             ({ classes }: WithStyles<DialogContentCssRules>) =>
-                <div className={classes.root}>
-                    <ProjectsTreePicker
-                        pickerId={this.props.commandInput.id}
-                        options={this.props.options}
-                        toggleItemActive={this.setProject} />
-                </div>
+                this.state.open ? <Dialog
+                    open={this.state.open}
+                    onClose={this.closeDialog}
+                    fullWidth
+                    data-cy="choose-a-project-dialog"
+                    maxWidth='md'>
+                    <DialogTitle>Choose a project</DialogTitle>
+                    <DialogContent className={classes.root}>
+                        <div className={classes.pickerWrapper}>
+                            <ProjectsTreePicker
+                                pickerId={this.props.commandInput.id}
+                                options={this.props.options}
+                                toggleItemActive={this.setProject} />
+                        </div>
+                    </DialogContent>
+                    <DialogActions>
+                        <Button onClick={this.closeDialog}>Cancel</Button>
+                        <Button
+                            disabled={this.invalid()}
+                            variant='contained'
+                            color='primary'
+                            onClick={this.submit}>Ok</Button>
+                    </DialogActions>
+                </Dialog> : null
         );
 
     });