|
@@ -23,8 +23,9 @@ const dataReader = async () => {
|
|
|
const Th = p =>
|
|
|
<div className='Th' {...p} />
|
|
|
|
|
|
+//<div className='Row' style={{position: 'relative',top}}>
|
|
|
const Row = ({top, children}) =>
|
|
|
-<div className='Row' style={{position: 'relative',top}}>
|
|
|
+<div className='Row' >
|
|
|
{children}
|
|
|
</div>
|
|
|
|
|
@@ -34,73 +35,6 @@ const Cell = ({children, ...props}) =>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
-function ModelGrid({model, rowHeight, gridHeight, overload, query, cellDoubleClick}){
|
|
|
- const onScreenRowCount = gridHeight/rowHeight
|
|
|
- const overloadedRowCount = overload * onScreenRowCount
|
|
|
-
|
|
|
- const [totalCount, setTotalCount] = useState(-1)
|
|
|
-
|
|
|
-
|
|
|
- const [gridContentRef, setGridContentRef] = useState()
|
|
|
- const [scroll, setScroll] = useState(0)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- const onScreenFirstRowIndex = Math.floor(scroll/rowHeight)
|
|
|
- let skip = onScreenFirstRowIndex - (overloadedRowCount - onScreenRowCount)/2;
|
|
|
-
|
|
|
- if (skip < 0) skip = 0
|
|
|
-
|
|
|
- const [sort, setSort] = useState([])
|
|
|
-
|
|
|
- const [records, setRecords] = useState()
|
|
|
- const cursorCalls = {skip: [skip], limit: [overloadedRowCount]}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if (sort.length) cursorCalls.sort = [sort]
|
|
|
-
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- if (totalCount > 0) {
|
|
|
- model.find(query, cursorCalls).then(records => setRecords(records))
|
|
|
- }
|
|
|
- },[model, query, sort, totalCount])
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- model && model.count(query).then(count => setTotalCount(count))
|
|
|
- },[model, query, totalCount])
|
|
|
-
|
|
|
- if (!model) return <>No model</>;
|
|
|
- return(
|
|
|
- <>
|
|
|
- <div className='GridHeader'>
|
|
|
- {model.fields.map(field => <Th onClick={e => (setSort(field.name === sort[0] ? [sort[0], -sort[1]] : [field.name, 1]), setRecords(null))}>{field.name}</Th>)}
|
|
|
- </div>
|
|
|
- <div className='GridViewport'
|
|
|
- onScroll={e => {
|
|
|
- if (Math.abs(e.target.scrollTop - scroll) > gridHeight*overload/3){
|
|
|
- setScroll(e.target.scrollTop);
|
|
|
- setRecords(null)
|
|
|
- } }}
|
|
|
- style={{maxHeight: gridHeight, height: gridHeight}}>
|
|
|
-
|
|
|
- <div className='GridContent'
|
|
|
- style={{height: totalCount*rowHeight}}
|
|
|
- ref={e => setGridContentRef(e)}>
|
|
|
- {console.log(records), records && records.map((record,i) =>
|
|
|
- <Row top={(skip)*rowHeight}>
|
|
|
- {model.fields.map(field =>
|
|
|
- <Cell onDoubleClick={e => cellDoubleClick(field.name, record[field.name], record._id)}>
|
|
|
- {record[field.name] === 'object' ? record[field.name].toString() : record[field.name]}
|
|
|
- </Cell>)}
|
|
|
- </Row>)}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </>
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
const ModelListItem = "div"
|
|
|
|
|
|
const ModelList = ({models, selected, onChange, Item=ModelListItem}) => {
|
|
@@ -131,7 +65,7 @@ const searchQueryBuilder = (search, model) => {
|
|
|
return {$or: model.fields.filter(field => field.type.kind == 'SCALAR').map(field => ({[field.name]: queryRegexp}))}
|
|
|
}
|
|
|
|
|
|
-const GridHeaderItem = ({field, sort, ...props}) =>
|
|
|
+const GridHeaderItem = ({field, sort:[sort], ...props}) =>
|
|
|
<div className="GridHeaderItem" {...props}>
|
|
|
{field.name in sort && sort[field.name] === -1 && '^ '}
|
|
|
{field.name}
|
|
@@ -145,6 +79,46 @@ const GridHeader = ({fields, sort, onSort}) =>
|
|
|
{fields.map(field => <GridHeaderItem field={field} sort={sort} onClick={() => onSort(field.name)}/>)}
|
|
|
</div>
|
|
|
|
|
|
+const VirtualScroll = ({gridHeight, count, rowHeight, row=Row, onScroll, records, skip}) => {
|
|
|
+ //const [records, setRecords] = useState([])
|
|
|
+ const limit = gridHeight/rowHeight
|
|
|
+ const Row = row
|
|
|
+
|
|
|
+
|
|
|
+ const timeout = useRef(0)
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='GridViewport'
|
|
|
+ onScroll={e => {
|
|
|
+ let skip = Math.ceil(e.target.scrollTop/rowHeight)
|
|
|
+ if (skip < 0) skip = 0
|
|
|
+ if (skip > count - limit) skip = count - limit
|
|
|
+
|
|
|
+ clearInterval(timeout.current)
|
|
|
+ timeout.current = setTimeout(() => {
|
|
|
+ console.log(skip, limit)
|
|
|
+ onScroll(skip,limit)
|
|
|
+ }, 1000)
|
|
|
+ }}
|
|
|
+ style={{maxHeight: gridHeight, height: gridHeight}} >
|
|
|
+ <div className='GridContent'
|
|
|
+ style={{height: count*rowHeight, minHeight: count*rowHeight, maxHeight: count*rowHeight}} >
|
|
|
+ <div style={{height: skip*rowHeight}} />
|
|
|
+ {records && records.map((record,i) =>
|
|
|
+ <Row key={i}>
|
|
|
+ {record.constructor.fields.map(field =>
|
|
|
+ <Cell>
|
|
|
+ {record[field.name] === 'object' ? record[field.name].toString() : record[field.name]}
|
|
|
+ </Cell>)}
|
|
|
+ </Row>)}
|
|
|
+ <div style={{height: (count - skip - records.length)*rowHeight}} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
const Grid = ({sort, scroll, gridHeight, overload, setScroll, count, rowHeight, records, skip, model, cellDoubleClick}) => {
|
|
|
const viewport = useRef()
|
|
|
return (
|
|
@@ -156,7 +130,7 @@ const Grid = ({sort, scroll, gridHeight, overload, setScroll, count, rowHeight,
|
|
|
//setRecords(null)
|
|
|
} }}
|
|
|
style={{maxHeight: gridHeight, height: gridHeight}}
|
|
|
- ref={viewport}>
|
|
|
+ ref={e => e && e.scrollTo(0,scroll)}>
|
|
|
|
|
|
<div className='GridContent'
|
|
|
style={{height: count*rowHeight, minHeight: count*rowHeight, maxHeight: count*rowHeight}} >
|
|
@@ -176,34 +150,25 @@ const Grid = ({sort, scroll, gridHeight, overload, setScroll, count, rowHeight,
|
|
|
|
|
|
|
|
|
const ModelView = ({model, components:Components={Search, Count, GridHeader, Grid}, rowHeight=50, gridHeight=500, overload=2}) => {
|
|
|
- const onScreenRowCount = Math.ceil(gridHeight/rowHeight)
|
|
|
- const overloadedRowCount = Math.ceil(overload * onScreenRowCount)
|
|
|
- const [scroll, setScroll] = useState(0)
|
|
|
-
|
|
|
-
|
|
|
|
|
|
- const onScreenFirstRowIndex = Math.floor(scroll/rowHeight)
|
|
|
- let skipAbove = Math.floor((overloadedRowCount - onScreenRowCount)/2);
|
|
|
- let skip = onScreenFirstRowIndex - skipAbove
|
|
|
|
|
|
|
|
|
- const [records, setRecords] = useState()
|
|
|
+ const [records, setRecords] = useState([])
|
|
|
|
|
|
|
|
|
const [search, setSearch] = useState("")
|
|
|
const [count, setCount] = useState(0)
|
|
|
|
|
|
- if (count - skip < overloadedRowCount) skip = count - overloadedRowCount
|
|
|
- if (skip < 0) skip = 0
|
|
|
-
|
|
|
const [query, setQuery] = useState({})
|
|
|
- const [cursorCalls, setCursorCalls] = useState({sort:[{}], skip: skip ? [skip] : undefined, limit: overloadedRowCount ? [overloadedRowCount] : undefined})
|
|
|
+ const [cursorCalls, setCursorCalls] = useState({sort:[{}], skip: [0], limit: [gridHeight/rowHeight]})
|
|
|
+
|
|
|
+ const skip = cursorCalls.skip[0]
|
|
|
|
|
|
console.log(cursorCalls)
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- setCursorCalls({sort:cursorCalls.sort, skip: skip ? [skip] : undefined, limit: overloadedRowCount ? [overloadedRowCount] : undefined})
|
|
|
- }, [scroll])
|
|
|
+ //useEffect(() => {
|
|
|
+ //setCursorCalls({sort:cursorCalls.sort, skip: skip ? [skip] : undefined, limit: overloadedRowCount ? [overloadedRowCount] : undefined})
|
|
|
+ //}, [scroll])
|
|
|
|
|
|
const timeout = useRef(0)
|
|
|
useEffect(() => {
|
|
@@ -229,10 +194,10 @@ const ModelView = ({model, components:Components={Search, Count, GridHeader, Gri
|
|
|
<GridHeader fields={model.fields}
|
|
|
sort={cursorCalls.sort}
|
|
|
onSort={sort => setCursorCalls({...cursorCalls,
|
|
|
- sort: {[sort]: cursorCalls.sort[sort] === 1 ? -1 : 1}
|
|
|
+ sort: [{[sort]: cursorCalls.sort[0][sort] === 1 ? -1 : 1}]
|
|
|
})}/>
|
|
|
|
|
|
- {records && <Grid
|
|
|
+ {/*records && <Grid
|
|
|
scroll={scroll}
|
|
|
setScroll={setScroll}
|
|
|
gridHeight={gridHeight}
|
|
@@ -242,7 +207,17 @@ const ModelView = ({model, components:Components={Search, Count, GridHeader, Gri
|
|
|
records={records}
|
|
|
skip={skip}
|
|
|
model={model}
|
|
|
- /> }
|
|
|
+ /> */}
|
|
|
+ {records && <VirtualScroll
|
|
|
+ skip={skip}
|
|
|
+ count={count}
|
|
|
+ records={records}
|
|
|
+ gridHeight={500}
|
|
|
+ rowHeight={50}
|
|
|
+ onScroll={(skip, limit) => {
|
|
|
+ model.find(query, {...cursorCalls, limit: [limit], skip: [skip]}).then(records => Promise.all(records)).then(records => setRecords(records)).then(() =>
|
|
|
+ setCursorCalls({...cursorCalls, limit: [limit], skip: [skip]}))
|
|
|
+ }}/> }
|
|
|
</>
|
|
|
)
|
|
|
}
|