Skip to content

Commit

Permalink
feat: add required prop to ui.file_upload #1503
Browse files Browse the repository at this point in the history
  • Loading branch information
marek-mihok committed Sep 21, 2022
1 parent 462aa67 commit f05c61e
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 10 deletions.
10 changes: 10 additions & 0 deletions py/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2892,6 +2892,7 @@ def __init__(
compact: Optional[bool] = None,
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
required: Optional[bool] = None,
):
_guard_scalar('FileUpload.name', name, (str,), True, False, False)
_guard_scalar('FileUpload.label', label, (str,), False, True, False)
Expand All @@ -2904,6 +2905,7 @@ def __init__(
_guard_scalar('FileUpload.compact', compact, (bool,), False, True, False)
_guard_scalar('FileUpload.visible', visible, (bool,), False, True, False)
_guard_scalar('FileUpload.tooltip', tooltip, (str,), False, True, False)
_guard_scalar('FileUpload.required', required, (bool,), False, True, False)
self.name = name
"""An identifying name for this component."""
self.label = label
Expand All @@ -2926,6 +2928,8 @@ def __init__(
"""True if the component should be visible. Defaults to True."""
self.tooltip = tooltip
"""An optional tooltip message displayed when a user clicks the help icon to the right of the component."""
self.required = required
"""True if this is a required field. Defaults to False."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
Expand All @@ -2940,6 +2944,7 @@ def dump(self) -> Dict:
_guard_scalar('FileUpload.compact', self.compact, (bool,), False, True, False)
_guard_scalar('FileUpload.visible', self.visible, (bool,), False, True, False)
_guard_scalar('FileUpload.tooltip', self.tooltip, (str,), False, True, False)
_guard_scalar('FileUpload.required', self.required, (bool,), False, True, False)
return _dump(
name=self.name,
label=self.label,
Expand All @@ -2952,6 +2957,7 @@ def dump(self) -> Dict:
compact=self.compact,
visible=self.visible,
tooltip=self.tooltip,
required=self.required,
)

@staticmethod
Expand Down Expand Up @@ -2979,6 +2985,8 @@ def load(__d: Dict) -> 'FileUpload':
_guard_scalar('FileUpload.visible', __d_visible, (bool,), False, True, False)
__d_tooltip: Any = __d.get('tooltip')
_guard_scalar('FileUpload.tooltip', __d_tooltip, (str,), False, True, False)
__d_required: Any = __d.get('required')
_guard_scalar('FileUpload.required', __d_required, (bool,), False, True, False)
name: str = __d_name
label: Optional[str] = __d_label
multiple: Optional[bool] = __d_multiple
Expand All @@ -2990,6 +2998,7 @@ def load(__d: Dict) -> 'FileUpload':
compact: Optional[bool] = __d_compact
visible: Optional[bool] = __d_visible
tooltip: Optional[str] = __d_tooltip
required: Optional[bool] = __d_required
return FileUpload(
name,
label,
Expand All @@ -3002,6 +3011,7 @@ def load(__d: Dict) -> 'FileUpload':
compact,
visible,
tooltip,
required,
)


Expand Down
3 changes: 3 additions & 0 deletions py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,7 @@ def file_upload(
compact: Optional[bool] = None,
visible: Optional[bool] = None,
tooltip: Optional[str] = None,
required: Optional[bool] = None,
) -> Component:
"""Create a file upload component.
A file upload component allows a user to browse, select and upload one or more files.
Expand All @@ -1139,6 +1140,7 @@ def file_upload(
compact: True if the component should be displayed compactly (without drag-and-drop capabilities). Defaults to False.
visible: True if the component should be visible. Defaults to True.
tooltip: An optional tooltip message displayed when a user clicks the help icon to the right of the component.
required: True if this is a required field. Defaults to False.
Returns:
A `h2o_wave.types.FileUpload` instance.
"""
Expand All @@ -1154,6 +1156,7 @@ def file_upload(
compact,
visible,
tooltip,
required,
))


Expand Down
8 changes: 6 additions & 2 deletions r/R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,7 @@ ui_mini_buttons <- function(
#' @param compact True if the component should be displayed compactly (without drag-and-drop capabilities). Defaults to False.
#' @param visible True if the component should be visible. Defaults to True.
#' @param tooltip An optional tooltip message displayed when a user clicks the help icon to the right of the component.
#' @param required True if this is a required field. Defaults to False.
#' @return A FileUpload instance.
#' @export
ui_file_upload <- function(
Expand All @@ -1337,7 +1338,8 @@ ui_file_upload <- function(
width = NULL,
compact = NULL,
visible = NULL,
tooltip = NULL) {
tooltip = NULL,
required = NULL) {
.guard_scalar("name", "character", name)
.guard_scalar("label", "character", label)
.guard_scalar("multiple", "logical", multiple)
Expand All @@ -1349,6 +1351,7 @@ ui_file_upload <- function(
.guard_scalar("compact", "logical", compact)
.guard_scalar("visible", "logical", visible)
.guard_scalar("tooltip", "character", tooltip)
.guard_scalar("required", "logical", required)
.o <- list(file_upload=list(
name=name,
label=label,
Expand All @@ -1360,7 +1363,8 @@ ui_file_upload <- function(
width=width,
compact=compact,
visible=visible,
tooltip=tooltip))
tooltip=tooltip,
required=required))
class(.o) <- append(class(.o), c(.wave_obj, "WaveComponent"))
return(.o)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@
<option name="Python" value="true"/>
</context>
</template>
<template name="w_full_file_upload" value="ui.file_upload(name='$name$',label='$label$',multiple=$multiple$,max_file_size=$max_file_size$,max_size=$max_size$,height='$height$',width='$width$',compact=$compact$,visible=$visible$,tooltip='$tooltip$',file_extensions=[&#10; $file_extensions$ &#10;]),$END$" description="Create Wave FileUpload with full attributes." toReformat="true" toShortenFQNames="true">
<template name="w_full_file_upload" value="ui.file_upload(name='$name$',label='$label$',multiple=$multiple$,max_file_size=$max_file_size$,max_size=$max_size$,height='$height$',width='$width$',compact=$compact$,visible=$visible$,tooltip='$tooltip$',required=$required$,file_extensions=[&#10; $file_extensions$ &#10;]),$END$" description="Create Wave FileUpload with full attributes." toReformat="true" toShortenFQNames="true">
<variable name="name" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="label" expression="" defaultValue="&quot;Upload&quot;" alwaysStopAt="true"/>
<variable name="multiple" expression="" defaultValue="&quot;False&quot;" alwaysStopAt="true"/>
Expand All @@ -1206,6 +1206,7 @@
<variable name="compact" expression="" defaultValue="&quot;False&quot;" alwaysStopAt="true"/>
<variable name="visible" expression="" defaultValue="&quot;True&quot;" alwaysStopAt="true"/>
<variable name="tooltip" expression="" defaultValue="" alwaysStopAt="true"/>
<variable name="required" expression="" defaultValue="&quot;False&quot;" alwaysStopAt="true"/>
<variable name="file_extensions" expression="" defaultValue="" alwaysStopAt="true"/>
<context>
<option name="Python" value="true"/>
Expand Down
2 changes: 1 addition & 1 deletion tools/vscode-extension/component-snippets.json
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,7 @@
"Wave Full FileUpload": {
"prefix": "w_full_file_upload",
"body": [
"ui.file_upload(name='$1', label='${2:Upload\"}', multiple=${3:False}, max_file_size=${4:None}, max_size=${5:None}, height='${6:300px}', width='${7:100%'}', compact=${8:False}, visible=${9:True}, tooltip='$10', file_extensions=[\n\t\t$11\t\t\n]),$0"
"ui.file_upload(name='$1', label='${2:Upload\"}', multiple=${3:False}, max_file_size=${4:None}, max_size=${5:None}, height='${6:300px}', width='${7:100%'}', compact=${8:False}, visible=${9:True}, tooltip='$10', required=${11:False}, file_extensions=[\n\t\t$12\t\t\n]),$0"
],
"description": "Create a full Wave FileUpload."
},
Expand Down
24 changes: 18 additions & 6 deletions ui/src/file_upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import * as Fluent from '@fluentui/react'
import { B, F, Id, S, U, xid } from 'h2o-wave'
import React from 'react'
import { stylesheet } from 'typestyle'
import { style, stylesheet } from 'typestyle'
import { centerMixin, clas, cssVar, dashed, padding } from './theme'
import { wave } from './ui'

Expand Down Expand Up @@ -46,6 +46,8 @@ export interface FileUpload {
visible?: B
/** An optional tooltip message displayed when a user clicks the help icon to the right of the component. */
tooltip?: S
/** True if this is a required field. Defaults to False. */
required?: B
}

const
Expand All @@ -72,9 +74,16 @@ const
minWidth: 80,
boxSizing: 'border-box',
height: 32,
display: 'inline-block'
},
asterisk: {
$nest: {
'&:hover': {
cursor: 'pointer'
'&::after': {
content: "'*'",
verticalAlign: 'top',
paddingLeft: '2px',
lineHeight: '12px',
position: 'absolute',
}
}
},
Expand Down Expand Up @@ -103,13 +112,14 @@ const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
XFileUpload = ({ model }: { model: FileUpload }) => {
const
{ name, label, file_extensions, max_file_size, compact, height, max_size, multiple } = model,
{ name, label, file_extensions, max_file_size, compact, height, max_size, multiple, required } = model,
[isDragging, setIsDragging] = React.useState(false),
[files, setFiles] = React.useState<File[]>([]),
[fileNames, setFileNames] = React.useState<S>(''),
[percentComplete, setPercentComplete] = React.useState(0.0),
[error, setError] = React.useState(''),
[successMsg, setSuccessMsg] = React.useState(''),
{ semanticColors: { errorText: errorTextColor } } = Fluent.useTheme(),
maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
Expand Down Expand Up @@ -304,7 +314,9 @@ export const
type='file'
accept={fileExtensions?.join(',')}
multiple={multiple} />
<label htmlFor={name} className={css.uploadLabel}>Browse...</label>
<div className={required ? clas(css.asterisk, style({ $nest: { '&::after': { color: errorTextColor } } })) : undefined}>
<label htmlFor={name} className={css.uploadLabel}>Browse...</label>
</div>
<Fluent.Text styles={{ root: { marginTop: 15 } }}>Or drag and drop {multiple ? 'files' : 'a file'} here.</Fluent.Text>
</>
)
Expand All @@ -328,7 +340,7 @@ export const
<>
{label && <Fluent.Label style={{ paddingTop: 6 }}>{label}</Fluent.Label>}
<div className={css.compact}>
<Fluent.TextField data-test={`textfield-${name}`} readOnly value={fileNames} errorMessage={error} />
<Fluent.TextField data-test={`textfield-${name}`} readOnly value={fileNames} errorMessage={error} required={required} />
<input id={name} data-test={name} type='file' hidden onChange={onChange} accept={fileExtensions?.join(',')} multiple={multiple} />
<label htmlFor={name} className={clas(css.uploadLabel, css.uploadLabelCompact)}>Browse</label>
</div>
Expand Down

0 comments on commit f05c61e

Please sign in to comment.