Skip to content

Commit e420204

Browse files
authored
Set isLoading the same way in all the viewers (#164)
* use cleaner 'void' prefix * ensure isLoading is set synchronously before fetching new data * remove unused loading state * remove unused setProgress prop * remove unnecessary dependency * replace loading with isLoading * harmonize where we set isLoading * fix lint
1 parent 2359daa commit e420204

File tree

10 files changed

+32
-79
lines changed

10 files changed

+32
-79
lines changed

packages/components/src/components/Cell.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,10 @@ interface CellProps {
1414
config?: CellConfig
1515
}
1616

17-
enum LoadingState {
18-
NotLoaded,
19-
Loading,
20-
Loaded,
21-
}
22-
2317
/**
2418
* Cell viewer displays a single cell from a table.
2519
*/
2620
export default function CellView({ source, row, col, config }: CellProps) {
27-
const [loading, setLoading] = useState<LoadingState>(LoadingState.NotLoaded)
2821
const [text, setText] = useState<string | undefined>()
2922
const [progress, setProgress] = useState<number>()
3023
const [error, setError] = useState<Error>()
@@ -57,17 +50,13 @@ export default function CellView({ source, row, col, config }: CellProps) {
5750
setError(error as Error)
5851
setText(undefined)
5952
} finally {
60-
setLoading(LoadingState.Loaded)
6153
setProgress(undefined)
6254
}
6355
}
6456

65-
if (loading === LoadingState.NotLoaded) {
66-
// use loading state to ensure we only load content once
67-
setLoading(LoadingState.Loading)
68-
loadCellData().catch(() => undefined)
69-
}
70-
}, [resolveUrl, requestInit, col, row, loading, setError])
57+
setProgress(0)
58+
void loadCellData()
59+
}, [resolveUrl, requestInit, col, row])
7160

7261
return (
7362
<Layout progress={progress} error={error} title={fileName}>

packages/components/src/components/Json.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,11 @@ function JsonObject({ obj, label }: { obj: object, label?: string }): ReactNode
7272
<span className={styles.object}>{'{'}</span>
7373
</div>
7474
<ul>
75-
{Object.entries(obj).map(([key, value]) => (
75+
{Object.entries(obj).map(([key, value]) =>
7676
<li key={key}>
7777
<Json json={value as unknown} label={key} />
78-
</li>
79-
))}
78+
</li>,
79+
)}
8080
</ul>
8181
<div className={styles.object}>{'}'}</div>
8282
</>

packages/components/src/components/viewers/CellPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export default function CellPanel({ df, row, col, setProgress, setError, onClose
3737
}
3838
}
3939

40-
loadCellData().catch(() => undefined)
40+
void loadCellData()
4141
}, [df, col, row, setProgress, setError])
4242

4343
const headers = <>

packages/components/src/components/viewers/ImageView.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ import { contentTypes, parseFileSize } from '../../lib/utils.js'
44
import { Spinner } from '../Layout.js'
55
import ContentHeader from './ContentHeader.js'
66

7-
enum LoadingState {
8-
NotLoaded,
9-
Loading,
10-
Loaded
11-
}
12-
137
interface ViewerProps {
148
source: FileSource
159
setError: (error: Error | undefined) => void
@@ -24,14 +18,15 @@ interface Content {
2418
* Image viewer component.
2519
*/
2620
export default function ImageView({ source, setError }: ViewerProps) {
27-
const [loading, setLoading] = useState(LoadingState.NotLoaded)
2821
const [content, setContent] = useState<Content>()
22+
const [isLoading, setIsLoading] = useState(true)
2923

3024
const { fileName, resolveUrl, requestInit } = source
3125

3226
useEffect(() => {
3327
async function loadContent() {
3428
try {
29+
setIsLoading(true)
3530
const res = await fetch(resolveUrl, requestInit)
3631
if (res.status === 401) {
3732
const text = await res.text()
@@ -50,16 +45,10 @@ export default function ImageView({ source, setError }: ViewerProps) {
5045
setContent(undefined)
5146
setError(error as Error)
5247
} finally {
53-
setLoading(LoadingState.Loaded)
48+
setIsLoading(false)
5449
}
5550
}
56-
57-
setLoading((loading) => {
58-
// use loading state to ensure we only load content once
59-
if (loading !== LoadingState.NotLoaded) return loading
60-
loadContent().catch(() => undefined)
61-
return LoadingState.Loading
62-
})
51+
void loadContent()
6352
}, [fileName, resolveUrl, requestInit, setError])
6453

6554
return <ContentHeader content={content}>
@@ -68,7 +57,7 @@ export default function ImageView({ source, setError }: ViewerProps) {
6857
className='image'
6958
src={content.dataUri} />}
7059

71-
{loading && <div className='center'><Spinner /></div>}
60+
{isLoading && <div className='center'><Spinner /></div>}
7261
</ContentHeader>
7362
}
7463

packages/components/src/components/viewers/JsonView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { useEffect, useState } from 'react'
22
import type { FileSource } from '../../lib/sources/types.js'
33
import { parseFileSize } from '../../lib/utils.js'
4+
import styles from '../../styles/Json.module.css'
45
import Json from '../Json.js'
56
import { Spinner } from '../Layout.js'
67
import ContentHeader, { TextContent } from './ContentHeader.js'
7-
import styles from '../../styles/Json.module.css'
88

99
interface ViewerProps {
1010
source: FileSource

packages/components/src/components/viewers/MarkdownView.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ import { Spinner } from '../Layout.js'
55
import Markdown from '../Markdown.js'
66
import ContentHeader, { TextContent } from './ContentHeader.js'
77

8-
enum LoadingState {
9-
NotLoaded,
10-
Loading,
11-
Loaded
12-
}
13-
148
interface ViewerProps {
159
source: FileSource
1610
setError: (error: Error | undefined) => void
@@ -20,15 +14,16 @@ interface ViewerProps {
2014
* Markdown viewer component.
2115
*/
2216
export default function MarkdownView({ source, setError }: ViewerProps) {
23-
const [loading, setLoading] = useState(LoadingState.NotLoaded)
2417
const [content, setContent] = useState<TextContent>()
18+
const [isLoading, setIsLoading] = useState(true)
2519

2620
const { resolveUrl, requestInit } = source
2721

2822
// Load markdown content
2923
useEffect(() => {
3024
async function loadContent() {
3125
try {
26+
setIsLoading(true)
3227
const res = await fetch(resolveUrl, requestInit)
3328
const text = await res.text()
3429
const fileSize = parseFileSize(res.headers) ?? text.length
@@ -43,21 +38,15 @@ export default function MarkdownView({ source, setError }: ViewerProps) {
4338
setError(error as Error)
4439
setContent(undefined)
4540
} finally {
46-
setLoading(LoadingState.Loaded)
41+
setIsLoading(false)
4742
}
4843
}
49-
50-
setLoading((loading) => {
51-
// use loading state to ensure we only load content once
52-
if (loading !== LoadingState.NotLoaded) return loading
53-
loadContent().catch(() => undefined)
54-
return LoadingState.Loading
55-
})
44+
void loadContent()
5645
}, [resolveUrl, requestInit, setError])
5746

5847
return <ContentHeader content={content}>
5948
<Markdown className='markdown' text={content?.text ?? ''} />
6049

61-
{ loading === LoadingState.Loading && <div className='center'><Spinner /></div> }
50+
{ isLoading && <div className='center'><Spinner /></div> }
6251
</ContentHeader>
6352
}

packages/components/src/components/viewers/ParquetView.tsx

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ import CellPanel from './CellPanel.js'
99
import ContentHeader, { ContentSize } from './ContentHeader.js'
1010
import SlidePanel, { SlidePanelConfig } from './SlidePanel.js'
1111

12-
enum LoadingState {
13-
NotLoaded,
14-
Loading,
15-
Loaded
16-
}
17-
1812
export type ParquetViewConfig = SlidePanelConfig & RoutesConfig
1913

2014
interface ViewerProps {
@@ -32,15 +26,16 @@ interface Content extends ContentSize {
3226
* Parquet file viewer
3327
*/
3428
export default function ParquetView({ source, setProgress, setError, config }: ViewerProps) {
35-
const [loading, setLoading] = useState<LoadingState>(LoadingState.NotLoaded)
29+
const [isLoading, setIsLoading] = useState<boolean>(true)
3630
const [content, setContent] = useState<Content>()
3731
const [cell, setCell] = useState<{ row: number, col: number } | undefined>()
3832

39-
const { resolveUrl, requestInit, sourceId } = source
4033
useEffect(() => {
4134
async function loadParquetDataFrame() {
4235
try {
36+
setIsLoading(true)
4337
setProgress(0.33)
38+
const { resolveUrl, requestInit } = source
4439
const asyncBuffer = await asyncBufferFromUrl({ url: resolveUrl, requestInit })
4540
const from = { url: resolveUrl, byteLength: asyncBuffer.byteLength, requestInit }
4641
setProgress(0.66)
@@ -52,20 +47,12 @@ export default function ParquetView({ source, setProgress, setError, config }: V
5247
} catch (error) {
5348
setError(error as Error)
5449
} finally {
55-
setLoading(LoadingState.Loaded)
50+
setIsLoading(false)
5651
setProgress(1)
5752
}
5853
}
59-
if (loading === LoadingState.NotLoaded) {
60-
setLoading(LoadingState.Loading)
61-
loadParquetDataFrame().catch(() => undefined)
62-
}
63-
}, [loading, resolveUrl, requestInit, setError, setProgress])
64-
65-
// Clear loading state on content change
66-
useEffect(() => {
67-
setLoading(LoadingState.NotLoaded)
68-
}, [source])
54+
void loadParquetDataFrame()
55+
}, [setError, setProgress, source])
6956

7057
// Close cell view on escape key
7158
useEffect(() => {
@@ -81,6 +68,7 @@ export default function ParquetView({ source, setProgress, setError, config }: V
8168
return () => { window.removeEventListener('keydown', handleKeyDown) }
8269
}, [cell])
8370

71+
const { sourceId } = source
8472
const getCellRouteUrl = useCallback(({ col, row }: {col: number, row: number}) => {
8573
const url = config?.routes?.getCellRouteUrl?.({ sourceId, col, row })
8674
if (url) {
@@ -108,13 +96,13 @@ export default function ParquetView({ source, setProgress, setError, config }: V
10896

10997
const mainContent = <ContentHeader content={content} headers={headers}>
11098
{content?.dataframe && <HighTable
111-
cacheKey={resolveUrl}
99+
cacheKey={source.resolveUrl}
112100
data={content.dataframe}
113101
onDoubleClickCell={onDoubleClickCell}
114102
onMouseDownCell={onMouseDownCell}
115103
onError={setError} />}
116104

117-
{loading === LoadingState.Loading && <div className='center'><Spinner /></div>}
105+
{isLoading && <div className='center'><Spinner /></div>}
118106
</ContentHeader>
119107

120108
let panelContent

packages/components/src/components/viewers/TextView.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import ContentHeader, { TextContent } from './ContentHeader.js'
77
interface ViewerProps {
88
source: FileSource
99
setError: (error: Error | undefined) => void
10-
setProgress: (progress: number | undefined) => void
1110
}
1211

1312
/**
@@ -41,8 +40,7 @@ export default function TextView({ source, setError }: ViewerProps) {
4140
setIsLoading(false)
4241
}
4342
}
44-
45-
loadContent().catch(() => undefined)
43+
void loadContent()
4644
}, [resolveUrl, requestInit, setError])
4745

4846
const headers = <>

packages/components/src/components/viewers/Viewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ export default function Viewer({
4545

4646
// Default to text viewer
4747
return (
48-
<TextView source={source} setError={setError} setProgress={setProgress} />
48+
<TextView source={source} setError={setError} />
4949
)
5050
}

packages/components/test/components/Folder.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ describe('Folder Component', () => {
152152

153153
// Type a search query and hit enter
154154
const searchInput = getByPlaceholderText('Search...')
155-
await act(async () => {
155+
act(() => {
156156
fireEvent.keyUp(searchInput, { target: { value: 'file1' } })
157157
})
158158

@@ -163,7 +163,7 @@ describe('Folder Component', () => {
163163
expect(location.href).toBe('/files?key=file1.txt')
164164
})
165165

166-
it('jumps to search box when user types /', async () => {
166+
it('jumps to search box when user types /', () => {
167167
const dirSource: DirSource = {
168168
sourceId: 'test-source',
169169
sourceParts: [{ text: 'test-source', sourceId: 'test-source' }],
@@ -179,7 +179,7 @@ describe('Folder Component', () => {
179179
expect(document.activeElement).toBe(searchInput)
180180

181181
// Typing inside the search box should work including /
182-
await act(async () => {
182+
act(() => {
183183
fireEvent.keyUp(searchInput, { target: { value: 'file1/' } })
184184
expect(searchInput.value).toBe('file1/')
185185
})

0 commit comments

Comments
 (0)