mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
feat: loading indicator
This commit is contained in:
parent
71e815bdca
commit
83815ea051
6 changed files with 92 additions and 38 deletions
|
|
@ -6,6 +6,7 @@ import { FileExplorer as FileExplorerCore } from '../driver/core'
|
|||
|
||||
import SearchBar from './SearchBar'
|
||||
import Node from './Node'
|
||||
import LoadingIndicator from './LoadingIndicator'
|
||||
|
||||
import cx from '../utils/cx'
|
||||
|
||||
|
|
@ -45,44 +46,53 @@ export default class FileExplorer extends React.Component {
|
|||
execAfterRender()
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.treeData !== this.props.treeData) {
|
||||
const { init } = nextProps
|
||||
init()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { execAfterRender } = this.props
|
||||
execAfterRender()
|
||||
}
|
||||
|
||||
renderFiles(visibleNodes, onNodeClick) {
|
||||
const { nodes, depths, focusedNode, expandedNodes } = visibleNodes
|
||||
if (nodes.length === 0) {
|
||||
return (
|
||||
<label className={'no-results'}>
|
||||
No results found.
|
||||
</label>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={'files'}>
|
||||
{nodes.map(node => (
|
||||
<Node
|
||||
key={node.path}
|
||||
node={node}
|
||||
depth={depths.get(node)}
|
||||
focused={focusedNode === node}
|
||||
expanded={expandedNodes.has(node)}
|
||||
onClick={onNodeClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
visibleNodes,
|
||||
freeze,
|
||||
handleKeyDown,
|
||||
handleSearchKeyChange,
|
||||
onNodeClick
|
||||
} = this.props
|
||||
const {
|
||||
nodes,
|
||||
depths,
|
||||
focusedNode,
|
||||
expandedNodes,
|
||||
} = visibleNodes || {}
|
||||
const { stateText, visibleNodes, freeze, handleKeyDown, handleSearchKeyChange, onNodeClick } = this.props
|
||||
return (
|
||||
<div className={cx(`file-explorer`, { freeze })} tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||
<SearchBar onSearchKeyChange={handleSearchKeyChange} />
|
||||
{!visibleNodes || !nodes || nodes.length === 0 ? (
|
||||
<label className={'no-results'}>No results found.</label>
|
||||
) : (
|
||||
<div className={'files'}>
|
||||
{nodes.map(node => (
|
||||
<Node
|
||||
key={node.path}
|
||||
node={node}
|
||||
depth={depths.get(node)}
|
||||
focused={focusedNode === node}
|
||||
expanded={expandedNodes.has(node)}
|
||||
onClick={onNodeClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
!visibleNodes || stateText
|
||||
? <LoadingIndicator text={stateText} />
|
||||
: this.renderFiles(visibleNodes, onNodeClick)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
13
src/components/LoadingIndicator.js
Normal file
13
src/components/LoadingIndicator.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react'
|
||||
import Icon from './Icon';
|
||||
|
||||
export default function LoadingIndicator({ text }) {
|
||||
return (
|
||||
<div className={'loading-indicator-container'}>
|
||||
<div className={'loading-indicator'}>
|
||||
<Icon className={'loading-indicator-icon'} type={'gear'} />
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -94,9 +94,8 @@ export default class Gitako extends React.PureComponent {
|
|||
{metaData && <MetaBar metaData={metaData} />}
|
||||
{errorDueToAuth && this.renderAccessDeniedError()}
|
||||
{metaData &&
|
||||
treeData && (
|
||||
<FileExplorer metaData={metaData} treeData={treeData} freeze={showSettings} accessToken={accessToken} compressSingletonFolder={compressSingletonFolder} />
|
||||
)}
|
||||
<FileExplorer metaData={metaData} treeData={treeData} freeze={showSettings} accessToken={accessToken} compressSingletonFolder={compressSingletonFolder} />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,6 +215,25 @@
|
|||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.loading-indicator-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.loading-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-indicator-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation: rotate 2s infinite linear;
|
||||
}
|
||||
}
|
||||
|
||||
.file-explorer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
@ -373,3 +392,11 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotateZ(0);
|
||||
} to {
|
||||
transform: rotateZ(360deg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,15 @@ const tasksAfterRender = []
|
|||
const visibleNodesGenerator = new VisibleNodesGenerator()
|
||||
|
||||
const init = dispatch => () => dispatch(async (state, { treeData, metaData, compressSingletonFolder }) => {
|
||||
if (!treeData) {
|
||||
dispatch(setStateText, 'Fetching Tree Data...')
|
||||
return
|
||||
}
|
||||
dispatch(setStateText, 'Rendering File List...')
|
||||
const { root } = treeParser.parse(treeData, metaData)
|
||||
visibleNodesGenerator.setCompress(compressSingletonFolder)
|
||||
await visibleNodesGenerator.plantTree(root)
|
||||
dispatch(setStateText, null)
|
||||
const currentPath = URLHelper.getCurrentPath(true)
|
||||
if (currentPath.length) {
|
||||
const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/'))
|
||||
|
|
@ -44,6 +50,10 @@ const execAfterRender = dispatch => () => {
|
|||
tasksAfterRender.length = 0
|
||||
}
|
||||
|
||||
const setStateText = dispatch => text => dispatch({
|
||||
stateText: text,
|
||||
})
|
||||
|
||||
const handleKeyDown = dispatch => ({ key }) => dispatch(({ visibleNodes: { nodes, focusedNode, expandedNodes, depths } }) => {
|
||||
if (focusedNode) {
|
||||
const focusedNodeIndex = nodes.indexOf(focusedNode)
|
||||
|
|
@ -174,6 +184,7 @@ const updateVisibleNodes = dispatch => () => {
|
|||
export default {
|
||||
init,
|
||||
execAfterRender,
|
||||
setStateText,
|
||||
handleKeyDown,
|
||||
handleSearchKeyChange,
|
||||
setExpand,
|
||||
|
|
|
|||
|
|
@ -16,15 +16,9 @@ const init = dispatch => async () => {
|
|||
dispatch(setMetaData, metaData)
|
||||
const shouldShow = URLHelper.isInCodePage(metaData)
|
||||
dispatch(setShouldShow, shouldShow)
|
||||
if (shouldShow) {
|
||||
DOMHelper.mountTopProgressBar()
|
||||
}
|
||||
const treeData = await GitHubHelper.getTreeData({ ...metaData, accessToken })
|
||||
dispatch({ logoContainerElement: DOMHelper.insertLogoMountPoint() })
|
||||
dispatch({ treeData })
|
||||
if (shouldShow) {
|
||||
DOMHelper.unmountTopProgressBar()
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: detect request time exceeds limit
|
||||
if (err.message === NOT_FOUND || err.message === BAD_CREDENTIALS) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue