7
7
FormCheckItem ,
8
8
FormLabel ,
9
9
FormTextInput ,
10
+ FormHeading ,
10
11
} from '../atoms/form'
11
12
import FormFolderSelector from '../atoms/FormFolderSelector'
12
13
import {
@@ -22,27 +23,35 @@ import { NoteDocEditibleProps } from '../../lib/db/types'
22
23
import { isFolderPathnameValid } from '../../lib/db/utils'
23
24
import { useDb } from '../../lib/db'
24
25
import { JsonObject } from 'type-fest'
25
- import { useRouter } from '../../lib/router'
26
26
import { filenamify } from '../../lib/string'
27
27
28
28
interface ImportLegacyNotesFormProps {
29
29
storageId : string
30
- onCancel : ( ) => void
31
30
}
32
31
33
- const ImportLegacyNotesForm = ( {
34
- storageId,
35
- onCancel,
36
- } : ImportLegacyNotesFormProps ) => {
32
+ const ImportLegacyNotesForm = ( { storageId } : ImportLegacyNotesFormProps ) => {
33
+ const { addAttachments, createFolder, createNote } = useDb ( )
34
+
37
35
const [ location , setLocation ] = useState ( '' )
36
+ const [ opened , setOpened ] = useState ( false )
37
+ const [ doneMessage , setDoneMessage ] = useState < string | null > ( null )
38
38
const [ errorMessage , setErrorMessage ] = useState ( null )
39
39
const [ convertingSnippetNotes , setConvertingSnippetNotes ] = useState ( true )
40
40
const [ destinationFolderPathname , setDestinationFolderPathname ] = useState (
41
41
'/imported'
42
42
)
43
43
const [ importing , setImporting ] = useState ( false )
44
- const { addAttachments, createFolder, createNote } = useDb ( )
45
- const { push } = useRouter ( )
44
+ const openForm = useCallback ( ( ) => {
45
+ setOpened ( true )
46
+ setDoneMessage ( null )
47
+ setErrorMessage ( null )
48
+ setConvertingSnippetNotes ( true )
49
+ setDestinationFolderPathname ( '/imported' )
50
+ } , [ ] )
51
+
52
+ const closeForm = useCallback ( ( ) => {
53
+ setOpened ( false )
54
+ } , [ ] )
46
55
47
56
const importNotes = useCallback ( async ( ) => {
48
57
if ( importing ) {
@@ -68,17 +77,22 @@ const ImportLegacyNotesForm = ({
68
77
)
69
78
)
70
79
71
- const noteFileNames = await readdir ( join ( location , 'notes' ) )
80
+ const noteFileNames = (
81
+ await readdir ( join ( location , 'notes' ) )
82
+ ) . filter ( ( fileName ) => fileName . match ( / \. c s o n $ / ) )
83
+
84
+ const invalidCsonFilePathnames : string [ ] = [ ]
72
85
const parsedNotes : [ string , JsonObject | null ] [ ] = await Promise . all (
73
86
noteFileNames . map ( async ( noteFileName ) => {
74
87
const noteFilePathname = join ( location , 'notes' , noteFileName )
75
- const rawCson = await readFileAsString ( noteFilePathname )
76
88
try {
89
+ const rawCson = await readFileAsString ( noteFilePathname )
77
90
const noteCson = parseCSON ( rawCson )
78
91
return [ noteFileName , noteCson ] as [ string , JsonObject ]
79
92
} catch ( error ) {
80
- console . error ( `Failed to parse ${ noteFilePathname } ` )
81
- console . error ( error )
93
+ console . warn ( `Failed to parse ${ noteFilePathname } ` )
94
+ console . warn ( error )
95
+ invalidCsonFilePathnames . push ( noteFilePathname )
82
96
return [ noteFileName , null ] as [ string , null ]
83
97
}
84
98
} )
@@ -113,15 +127,28 @@ const ImportLegacyNotesForm = ({
113
127
const attachmentNameTupleList : [ string , string ] [ ] = [ ]
114
128
await Promise . all (
115
129
attachmentFileNames . map ( async ( fileName ) => {
116
- const result = await readFile (
117
- join ( noteAttachmentsFolderPathname , fileName )
130
+ const attachmentPathname = join (
131
+ noteAttachmentsFolderPathname ,
132
+ fileName
118
133
)
134
+ try {
135
+ const result = await readFile ( attachmentPathname )
119
136
120
- const file = await convertBufferToFile ( result , fileName )
137
+ const file = await convertBufferToFile ( result , fileName )
121
138
122
- const [ attachment ] = await addAttachments ( storageId , [ file ] )
139
+ const [ attachment ] = await addAttachments ( storageId , [ file ] )
123
140
124
- attachmentNameTupleList . push ( [ fileName , attachment . name ] )
141
+ attachmentNameTupleList . push ( [ fileName , attachment . name ] )
142
+ } catch ( error ) {
143
+ switch ( error . code ) {
144
+ case 'EISDIR' :
145
+ break
146
+ default :
147
+ console . warn (
148
+ `Failed to add ${ attachmentPathname } attachment`
149
+ )
150
+ }
151
+ }
125
152
} )
126
153
)
127
154
@@ -187,11 +214,14 @@ const ImportLegacyNotesForm = ({
187
214
await createNote ( storageId , note )
188
215
}
189
216
190
- push (
191
- `/app/storages/${ storageId } /notes${
192
- destinationFolderPathname === '/' ? '' : destinationFolderPathname
217
+ setDoneMessage (
218
+ `The notes are imported to ${ destinationFolderPathname } ${
219
+ invalidCsonFilePathnames . length > 0
220
+ ? ` (${ invalidCsonFilePathnames . length } invalid file(s). Please check console in developer tool to know more)`
221
+ : ''
193
222
} `
194
223
)
224
+ setOpened ( false )
195
225
} catch ( error ) {
196
226
setErrorMessage ( error . message )
197
227
console . error ( error )
@@ -206,7 +236,6 @@ const ImportLegacyNotesForm = ({
206
236
createFolder ,
207
237
createNote ,
208
238
importing ,
209
- push ,
210
239
] )
211
240
212
241
const updateConvertingSnippetNotes = useCallback (
@@ -225,34 +254,48 @@ const ImportLegacyNotesForm = ({
225
254
226
255
return (
227
256
< >
228
- { errorMessage != null && (
229
- < FormBlockquote variant = 'danger' > { errorMessage } </ FormBlockquote >
257
+ < FormHeading depth = { 2 } > Import Notes from Legacy BoostNote</ FormHeading >
258
+ { opened ? (
259
+ < >
260
+ { errorMessage != null && (
261
+ < FormBlockquote variant = 'danger' > { errorMessage } </ FormBlockquote >
262
+ ) }
263
+ < FormGroup >
264
+ < FormLabel > Legacy Storage Location</ FormLabel >
265
+ < FormFolderSelector value = { location } setValue = { setLocation } />
266
+ </ FormGroup >
267
+ < FormGroup >
268
+ < FormLabel > Destination Folder</ FormLabel >
269
+ < FormTextInput
270
+ value = { destinationFolderPathname }
271
+ onChange = { updateDestinationFolderPathname }
272
+ />
273
+ </ FormGroup >
274
+ < FormGroup >
275
+ < FormCheckItem
276
+ id = 'convertingSnippetNotes-checkbox'
277
+ type = 'checkbox'
278
+ checked = { convertingSnippetNotes }
279
+ onChange = { updateConvertingSnippetNotes }
280
+ >
281
+ Converting snippet notes
282
+ </ FormCheckItem >
283
+ </ FormGroup >
284
+ < FormGroup >
285
+ < FormPrimaryButton onClick = { importNotes } > Import</ FormPrimaryButton >
286
+ < FormSecondaryButton onClick = { closeForm } >
287
+ Cancel
288
+ </ FormSecondaryButton >
289
+ </ FormGroup >
290
+ </ >
291
+ ) : (
292
+ < FormGroup >
293
+ { doneMessage != null && (
294
+ < FormBlockquote variant = 'primary' > { doneMessage } </ FormBlockquote >
295
+ ) }
296
+ < FormSecondaryButton onClick = { openForm } > Import</ FormSecondaryButton >
297
+ </ FormGroup >
230
298
) }
231
- < FormGroup >
232
- < FormLabel > Legacy Storage Location</ FormLabel >
233
- < FormFolderSelector value = { location } setValue = { setLocation } />
234
- </ FormGroup >
235
- < FormGroup >
236
- < FormLabel > Destination Folder</ FormLabel >
237
- < FormTextInput
238
- value = { destinationFolderPathname }
239
- onChange = { updateDestinationFolderPathname }
240
- />
241
- </ FormGroup >
242
- < FormGroup >
243
- < FormCheckItem
244
- id = 'convertingSnippetNotes-checkbox'
245
- type = 'checkbox'
246
- checked = { convertingSnippetNotes }
247
- onChange = { updateConvertingSnippetNotes }
248
- >
249
- Converting snippet notes
250
- </ FormCheckItem >
251
- </ FormGroup >
252
- < FormGroup >
253
- < FormPrimaryButton onClick = { importNotes } > Import</ FormPrimaryButton >
254
- < FormSecondaryButton onClick = { onCancel } > Cancel</ FormSecondaryButton >
255
- </ FormGroup >
256
299
</ >
257
300
)
258
301
}
0 commit comments