Skip to content

Commit

Permalink
Merge pull request #809 from interval/remote-pagination-v2
Browse files Browse the repository at this point in the history
Progressive table data fetching
  • Loading branch information
danphilibin authored Sep 14, 2022
2 parents d3f5007 + 0f1cb48 commit b963332
Show file tree
Hide file tree
Showing 9 changed files with 576 additions and 127 deletions.
3 changes: 2 additions & 1 deletion src/classes/IOClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
} from './IOPromise'
import IOError from './IOError'
import spreadsheet from '../components/spreadsheet'
import { selectTable, displayTable } from '../components/table'
import displayTable from '../components/displayTable'
import selectTable from '../components/selectTable'
import selectSingle from '../components/selectSingle'
import search from '../components/search'
import selectMultiple from '../components/selectMultiple'
Expand Down
72 changes: 72 additions & 0 deletions src/components/displayTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { z } from 'zod'
import Logger from '../classes/Logger'
import { tableRow, T_IO_PROPS, menuItem, T_IO_STATE } from '../ioSchema'
import { TableColumn } from '../types'
import {
columnsBuilder,
tableRowSerializer,
filterRows,
sortRows,
TABLE_DATA_BUFFER_SIZE,
missingColumnMessage,
} from '../utils/table'

type PublicProps<Row> = Omit<
T_IO_PROPS<'DISPLAY_TABLE'>,
'data' | 'columns' | 'totalRecords'
> & {
data: Row[]
columns?: (TableColumn<Row> | string)[]
rowMenuItems?: (row: Row) => z.infer<typeof menuItem>[]
}

export default function displayTable(logger: Logger) {
return function displayTable<Row extends z.input<typeof tableRow> = any>(
props: PublicProps<Row>
) {
const columns = columnsBuilder(props, column =>
logger.error(missingColumnMessage('io.display.table')(column))
)

// Rendering all rows on initialization is necessary for filtering and sorting
const data = props.data.map((row, index) =>
tableRowSerializer({
index,
row,
columns,
menuBuilder: props.rowMenuItems,
})
)

return {
props: {
...props,
data: data.slice(0, TABLE_DATA_BUFFER_SIZE),
totalRecords: data.length,
columns,
} as T_IO_PROPS<'DISPLAY_TABLE'>,
async onStateChange(newState: T_IO_STATE<'DISPLAY_TABLE'>) {
const filtered = filterRows({
queryTerm: newState.queryTerm,
data,
})

const sorted = sortRows({
data: filtered,
column: newState.sortColumn ?? null,
direction: newState.sortDirection ?? null,
})

return {
...props,
data: sorted.slice(
newState.offset,
newState.offset + TABLE_DATA_BUFFER_SIZE
),
totalRecords: sorted.length,
columns: columns.map(c => ({ label: c.label })),
}
},
}
}
}
86 changes: 86 additions & 0 deletions src/components/selectTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { z } from 'zod'
import Logger from '../classes/Logger'
import {
tableRow,
T_IO_PROPS,
menuItem,
T_IO_RETURNS,
T_IO_STATE,
} from '../ioSchema'
import { TableColumn } from '../types'
import {
columnsBuilder,
filterRows,
tableRowSerializer,
sortRows,
TABLE_DATA_BUFFER_SIZE,
missingColumnMessage,
} from '../utils/table'

type PublicProps<Row> = Omit<T_IO_PROPS<'SELECT_TABLE'>, 'data' | 'columns'> & {
data: Row[]
columns?: (TableColumn<Row> | string)[]
rowMenuItems?: (row: Row) => z.infer<typeof menuItem>[]
}

export default function selectTable(logger: Logger) {
return function <Row extends z.input<typeof tableRow> = any>(
props: PublicProps<Row>
) {
type DataList = typeof props['data']

const columns = columnsBuilder(props, column =>
logger.error(missingColumnMessage('io.select.table')(column))
)

// Rendering all rows on initialization is necessary for filtering and sorting
const data = props.data.map((row, index) =>
tableRowSerializer({
index,
row,
columns,
menuBuilder: props.rowMenuItems,
})
)

return {
props: {
...props,
data: data.slice(0, TABLE_DATA_BUFFER_SIZE),
totalRecords: data.length,
columns,
},
getValue(response: T_IO_RETURNS<'SELECT_TABLE'>) {
const indices = response.map(({ key }) => Number(key))
const rows = props.data.filter((_, idx) => indices.includes(idx))
return rows as DataList
},
async onStateChange(newState: T_IO_STATE<'SELECT_TABLE'>) {
const filtered = filterRows({ queryTerm: newState.queryTerm, data })

const sorted = sortRows({
data: filtered,
column: newState.sortColumn ?? null,
direction: newState.sortDirection ?? null,
})

let selectedKeys: string[] = []

if (newState.isSelectAll) {
selectedKeys = sorted.map(({ key }) => key)
}

return {
...props,
data: sorted.slice(
newState.offset,
newState.offset + TABLE_DATA_BUFFER_SIZE
),
totalRecords: sorted.length,
selectedKeys,
columns,
}
},
}
}
}
94 changes: 0 additions & 94 deletions src/components/table.ts

This file was deleted.

18 changes: 8 additions & 10 deletions src/examples/basic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ import {
} from '../../types'
import editEmailForUser from './editEmail'
import { fakeDb, mapToIntervalUser, sleep } from '../utils/helpers'
import {
table_basic,
table_custom_columns,
table_custom,
table_actions,
} from './selectFromTable'
import * as table_actions from './table'
import unauthorized from './unauthorized'
import './ghostHost'
import { generateS3Urls } from '../utils/upload'
import fs from 'fs'
import { ActionGroup } from '../../experimental'

const actionLinks: IntervalActionHandler = async () => {
await io.group([
Expand Down Expand Up @@ -232,10 +228,6 @@ const interval = new Interval({
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet quam in lorem sagittis accumsan malesuada nec mauris. Nulla cursus dolor id augue sodales, et consequat elit mattis. Suspendisse nec sollicitudin ex. Pellentesque laoreet nulla nec malesuada consequat. Donec blandit leo id tincidunt tristique. Mauris vehicula metus sed ex bibendum, nec bibendum urna tincidunt. Curabitur porttitor euismod velit sed interdum. Suspendisse at dapibus eros. Vestibulum varius, est vel luctus pellentesque, risus lorem ullamcorper est, a ullamcorper metus dolor eget neque. Donec sit amet nulla tempus, fringilla magna eu, bibendum tortor. Nam pulvinar diam id vehicula posuere. Praesent non turpis et nibh dictum suscipit non nec ante. Phasellus vulputate egestas nisl a dapibus. Duis augue lorem, mattis auctor condimentum a, convallis sed elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque bibendum, magna vel pharetra fermentum, eros mi vulputate enim, in consectetur est quam quis felis.',
}
},
table_actions,
table_basic,
table_custom,
table_custom_columns,
// 'progress-through-long-list': async io => {
// const resp = await io.experimental.progressThroughList(
// 'Here are some items',
Expand Down Expand Up @@ -961,6 +953,12 @@ const interval = new Interval({
return 'All done!'
},
},
groups: {
tables: new ActionGroup({
name: 'Tables',
actions: table_actions,
}),
},
})

interval.listen()
Loading

0 comments on commit b963332

Please sign in to comment.