11// a component that displays the dataset reference including edit-in-place UI
22// for dataset rename
33import * as React from 'react'
4+ import { AnyAction } from 'redux'
45import classNames from 'classnames'
56
6- import { ApiActionThunk } from '../store/api'
77import { QriRef } from '../models/qriRef'
88
99import { connectComponentToPropsWithRouter } from '../utils/connectComponentToProps'
10- import { validateDatasetName } from '../utils/formValidation'
10+ import { validateDatasetName , ValidationError } from '../utils/formValidation'
1111
1212import { renameDataset } from '../actions/api'
1313
1414interface DatasetReferenceProps {
15+ /**
16+ * the qriRef is particularly important in this component: it's where we get
17+ * the username and original dataset name
18+ */
1519 qriRef : QriRef
16- renameDataset : ( username : string , name : string , newName : string ) => ApiActionThunk
20+ /**
21+ * the optional isValid function allows us to inject additional actions when
22+ * the dataset rename has been validated or invalidated
23+ */
24+ isValid ?: ( err : ValidationError ) => void
25+ /**
26+ * if used as a container, the DatasetReference will get the `renameDataset`
27+ * api action as it's submit function. The `DatasetReferenceComponent` may
28+ * or may not use the onSubmit action
29+ */
30+ onSubmit ?: ( username : string , name : string , newName : string ) => Promise < AnyAction >
31+ /**
32+ * the optional onChange function allows us to inject additional actions when
33+ * any input has changed
34+ */
35+ onChange ?: ( newName : string ) => void
36+ /**
37+ * if focusOnFirstRender is true, the dataset name input will be focused when the
38+ * component is first rendered
39+ */
40+ focusOnFirstRender ?: boolean
1741}
1842
19- const DatasetReferenceComponent : React . FunctionComponent < DatasetReferenceProps > = ( props ) => {
20- const { qriRef, renameDataset } = props
43+ export const DatasetReferenceComponent : React . FunctionComponent < DatasetReferenceProps > = ( props ) => {
44+ const {
45+ qriRef,
46+ onSubmit,
47+ onChange,
48+ isValid,
49+ focusOnFirstRender = false
50+ } = props
51+
2152 const { username, name } = qriRef
22- const [ nameEditing , setNameEditing ] = React . useState ( false )
53+ const [ nameEditing , setNameEditing ] = React . useState ( focusOnFirstRender )
2354 const [ newName , setNewName ] = React . useState ( name )
24- const [ inValid , setInvalid ] = React . useState ( null )
55+ const [ invalidErr , setInvalidErr ] = React . useState < ValidationError | null > ( null )
2556
2657 const datasetSelected = username !== '' && name !== ''
2758
59+ // use a ref so we can set up a click handler
60+ const nameRef : any = React . useRef ( null )
61+
2862 const confirmRename = ( username : string , name : string , newName : string ) => {
2963 // cancel if no change, change invalid, or empty
30- if ( ( name === newName ) || inValid || newName === '' ) {
64+ if ( ( name === newName ) || invalidErr || newName === '' ) {
3165 cancelRename ( )
3266 } else {
33- renameDataset ( username , name , newName )
34- . then ( ( ) => {
35- setNameEditing ( false )
36- } )
67+ if ( onSubmit ) {
68+ onSubmit ( username , name , newName )
69+ . then ( ( ) => {
70+ setNameEditing ( false )
71+ } )
72+ return
73+ }
74+ setNameEditing ( false )
3775 }
3876 }
3977
4078 const cancelRename = ( ) => {
4179 setNewName ( name )
42- setInvalid ( null )
80+ onChange && onChange ( name )
81+ setInvalidErr ( null )
82+ isValid && isValid ( null )
4383 setNameEditing ( false )
4484 }
4585
46- const handleKeyDown = ( e : any ) => {
86+ const handleKeyDown = ( e : KeyboardEvent ) => {
4787 // cancel on esc
4888 if ( e . keyCode === 27 ) {
4989 cancelRename ( )
@@ -55,9 +95,6 @@ const DatasetReferenceComponent: React.FunctionComponent<DatasetReferenceProps>
5595 }
5696 }
5797
58- // use a ref so we can set up a click handler
59- const nameRef : any = React . useRef ( null )
60-
6198 const handleMousedown = ( e : MouseEvent ) => {
6299 const { target } = e
63100 // allows the user to resize the sidebar when editing the dataset name
@@ -85,8 +122,11 @@ const DatasetReferenceComponent: React.FunctionComponent<DatasetReferenceProps>
85122
86123 const handleInputChange = ( e : any ) => {
87124 let { value } = e . target
88- setInvalid ( validateDatasetName ( value ) )
125+ const err = validateDatasetName ( value )
126+ setInvalidErr ( err )
127+ isValid && isValid ( err )
89128 setNewName ( value )
129+ onChange && onChange ( value )
90130 }
91131
92132 // when the input is focused, set the cursor to the left, and scroll all the way to the left
@@ -101,7 +141,7 @@ const DatasetReferenceComponent: React.FunctionComponent<DatasetReferenceProps>
101141 < div className = { classNames ( 'dataset-name' , { 'no-pointer' : ! datasetSelected } ) } id = 'dataset-name' ref = { nameRef } >
102142 { nameEditing && datasetSelected && < input
103143 id = 'dataset-name-input'
104- className = { classNames ( { invalid : inValid } ) }
144+ className = { classNames ( { invalid : invalidErr } ) }
105145 type = 'text'
106146 value = { newName }
107147 maxLength = { 150 }
@@ -119,5 +159,5 @@ const DatasetReferenceComponent: React.FunctionComponent<DatasetReferenceProps>
119159export default connectComponentToPropsWithRouter < DatasetReferenceProps > (
120160 DatasetReferenceComponent ,
121161 { } ,
122- { renameDataset }
162+ { onSubmit : renameDataset }
123163)
0 commit comments