Use frontend-core implementation of data fetching in backend UI
This commit is contained in:
parent
c7cd6b923d
commit
05e9f6088b
|
@ -14,18 +14,19 @@
|
||||||
import Table from "./Table.svelte"
|
import Table from "./Table.svelte"
|
||||||
import { TableNames } from "constants"
|
import { TableNames } from "constants"
|
||||||
import CreateEditRow from "./modals/CreateEditRow.svelte"
|
import CreateEditRow from "./modals/CreateEditRow.svelte"
|
||||||
import { fetchTableData } from "helpers/fetchTableData"
|
|
||||||
import { Pagination } from "@budibase/bbui"
|
import { Pagination } from "@budibase/bbui"
|
||||||
|
import { fetchData } from "@budibase/frontend-core"
|
||||||
|
import { API } from "api"
|
||||||
|
|
||||||
let hideAutocolumns = true
|
let hideAutocolumns = true
|
||||||
|
|
||||||
$: isUsersTable = $tables.selected?._id === TableNames.USERS
|
$: isUsersTable = $tables.selected?._id === TableNames.USERS
|
||||||
$: type = $tables.selected?.type
|
$: type = $tables.selected?.type
|
||||||
$: isInternal = type !== "external"
|
$: isInternal = type !== "external"
|
||||||
$: schema = $tables.selected?.schema
|
$: schema = $tables.selected?.schema
|
||||||
$: enrichedSchema = enrichSchema($tables.selected?.schema)
|
$: enrichedSchema = enrichSchema($tables.selected?.schema)
|
||||||
$: id = $tables.selected?._id
|
$: id = $tables.selected?._id
|
||||||
$: search = searchTable(id)
|
$: fetch = createFetch(id)
|
||||||
$: columnOptions = Object.keys($search.schema || {})
|
|
||||||
|
|
||||||
const enrichSchema = schema => {
|
const enrichSchema = schema => {
|
||||||
let tempSchema = { ...schema }
|
let tempSchema = { ...schema }
|
||||||
|
@ -47,18 +48,24 @@
|
||||||
return tempSchema
|
return tempSchema
|
||||||
}
|
}
|
||||||
// Fetches new data whenever the table changes
|
// Fetches new data whenever the table changes
|
||||||
const searchTable = tableId => {
|
const createFetch = tableId => {
|
||||||
return fetchTableData({
|
return fetchData({
|
||||||
|
API,
|
||||||
|
datasource: {
|
||||||
tableId,
|
tableId,
|
||||||
|
type: "table",
|
||||||
|
},
|
||||||
|
options: {
|
||||||
schema,
|
schema,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
paginate: true,
|
paginate: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch data whenever sorting option changes
|
// Fetch data whenever sorting option changes
|
||||||
const onSort = e => {
|
const onSort = e => {
|
||||||
search.update({
|
fetch.update({
|
||||||
sortColumn: e.detail.column,
|
sortColumn: e.detail.column,
|
||||||
sortOrder: e.detail.order,
|
sortOrder: e.detail.order,
|
||||||
})
|
})
|
||||||
|
@ -66,22 +73,20 @@
|
||||||
|
|
||||||
// Fetch data whenever filters change
|
// Fetch data whenever filters change
|
||||||
const onFilter = e => {
|
const onFilter = e => {
|
||||||
search.update({
|
fetch.update({
|
||||||
filters: e.detail,
|
filter: e.detail,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch data whenever schema changes
|
// Fetch data whenever schema changes
|
||||||
const onUpdateColumns = () => {
|
const onUpdateColumns = () => {
|
||||||
search.update({
|
fetch.refresh()
|
||||||
schema,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch data whenever rows are modified. Unfortunately we have to lose
|
// Fetch data whenever rows are modified. Unfortunately we have to lose
|
||||||
// our pagination place, as our bookmarks will have shifted.
|
// our pagination place, as our bookmarks will have shifted.
|
||||||
const onUpdateRows = () => {
|
const onUpdateRows = () => {
|
||||||
search.update()
|
fetch.update()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -91,9 +96,9 @@
|
||||||
schema={enrichedSchema}
|
schema={enrichedSchema}
|
||||||
{type}
|
{type}
|
||||||
tableId={id}
|
tableId={id}
|
||||||
data={$search.rows}
|
data={$fetch.rows}
|
||||||
bind:hideAutocolumns
|
bind:hideAutocolumns
|
||||||
loading={$search.loading}
|
loading={$fetch.loading}
|
||||||
on:sort={onSort}
|
on:sort={onSort}
|
||||||
allowEditing
|
allowEditing
|
||||||
disableSorting
|
disableSorting
|
||||||
|
@ -138,11 +143,11 @@
|
||||||
<div in:fade={{ delay: 200, duration: 100 }}>
|
<div in:fade={{ delay: 200, duration: 100 }}>
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
<Pagination
|
<Pagination
|
||||||
page={$search.pageNumber + 1}
|
page={$fetch.pageNumber + 1}
|
||||||
hasPrevPage={$search.hasPrevPage}
|
hasPrevPage={$fetch.hasPrevPage}
|
||||||
hasNextPage={$search.hasNextPage}
|
hasNextPage={$fetch.hasNextPage}
|
||||||
goToPrevPage={$search.loading ? null : search.prevPage}
|
goToPrevPage={$fetch.loading ? null : fetch.prevPage}
|
||||||
goToNextPage={$search.loading ? null : search.nextPage}
|
goToNextPage={$fetch.loading ? null : fetch.nextPage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
// Do not use any aliased imports in common files, as these will be bundled
|
|
||||||
// by multiple bundlers which may not be able to resolve them.
|
|
||||||
// This will eventually be replaced by the new client implementation when we
|
|
||||||
// add a core package.
|
|
||||||
import { writable, derived, get } from "svelte/store"
|
|
||||||
import { API } from "api"
|
|
||||||
import { LuceneUtils } from "@budibase/frontend-core"
|
|
||||||
|
|
||||||
const defaultOptions = {
|
|
||||||
tableId: null,
|
|
||||||
filters: null,
|
|
||||||
limit: 10,
|
|
||||||
sortColumn: null,
|
|
||||||
sortOrder: "ascending",
|
|
||||||
paginate: true,
|
|
||||||
schema: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchTableData = opts => {
|
|
||||||
// Save option set so we can override it later rather than relying on params
|
|
||||||
let options = {
|
|
||||||
...defaultOptions,
|
|
||||||
...opts,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local non-observable state
|
|
||||||
let query
|
|
||||||
let sortType
|
|
||||||
let lastBookmark
|
|
||||||
|
|
||||||
// Local observable state
|
|
||||||
const store = writable({
|
|
||||||
rows: [],
|
|
||||||
schema: null,
|
|
||||||
loading: false,
|
|
||||||
loaded: false,
|
|
||||||
bookmarks: [],
|
|
||||||
pageNumber: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Derive certain properties to return
|
|
||||||
const derivedStore = derived(store, $store => {
|
|
||||||
return {
|
|
||||||
...$store,
|
|
||||||
hasNextPage: $store.bookmarks[$store.pageNumber + 1] != null,
|
|
||||||
hasPrevPage: $store.pageNumber > 0,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const fetchPage = async bookmark => {
|
|
||||||
lastBookmark = bookmark
|
|
||||||
const { tableId, limit, sortColumn, sortOrder, paginate } = options
|
|
||||||
return await API.searchTable({
|
|
||||||
tableId,
|
|
||||||
query,
|
|
||||||
limit,
|
|
||||||
sort: sortColumn,
|
|
||||||
sortOrder: sortOrder?.toLowerCase() ?? "ascending",
|
|
||||||
sortType,
|
|
||||||
paginate,
|
|
||||||
bookmark,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches a fresh set of results from the server
|
|
||||||
const fetchData = async () => {
|
|
||||||
const { tableId, schema, sortColumn, filters } = options
|
|
||||||
|
|
||||||
// Ensure table ID exists
|
|
||||||
if (!tableId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get and enrich schema.
|
|
||||||
// Ensure there are "name" properties for all fields and that field schema
|
|
||||||
// are objects
|
|
||||||
let enrichedSchema = schema
|
|
||||||
if (!enrichedSchema) {
|
|
||||||
const definition = await API.fetchTableDefinition(tableId)
|
|
||||||
enrichedSchema = definition?.schema ?? null
|
|
||||||
}
|
|
||||||
if (enrichedSchema) {
|
|
||||||
Object.entries(schema).forEach(([fieldName, fieldSchema]) => {
|
|
||||||
if (typeof fieldSchema === "string") {
|
|
||||||
enrichedSchema[fieldName] = {
|
|
||||||
type: fieldSchema,
|
|
||||||
name: fieldName,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
enrichedSchema[fieldName] = {
|
|
||||||
...fieldSchema,
|
|
||||||
name: fieldName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Save fixed schema so we can provide it later
|
|
||||||
options.schema = enrichedSchema
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure schema exists
|
|
||||||
if (!schema) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
store.update($store => ({ ...$store, schema, loading: true }))
|
|
||||||
|
|
||||||
// Work out what sort type to use
|
|
||||||
if (!sortColumn || !schema[sortColumn]) {
|
|
||||||
sortType = "string"
|
|
||||||
}
|
|
||||||
const type = schema?.[sortColumn]?.type
|
|
||||||
sortType = type === "number" ? "number" : "string"
|
|
||||||
|
|
||||||
// Build the lucene query
|
|
||||||
query = LuceneUtils.buildLuceneQuery(filters)
|
|
||||||
|
|
||||||
// Actually fetch data
|
|
||||||
const page = await fetchPage()
|
|
||||||
store.update($store => ({
|
|
||||||
...$store,
|
|
||||||
loading: false,
|
|
||||||
loaded: true,
|
|
||||||
pageNumber: 0,
|
|
||||||
rows: page.rows,
|
|
||||||
bookmarks: page.hasNextPage ? [null, page.bookmark] : [null],
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the next page of data
|
|
||||||
const nextPage = async () => {
|
|
||||||
const state = get(derivedStore)
|
|
||||||
if (state.loading || !options.paginate || !state.hasNextPage) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch next page
|
|
||||||
store.update($store => ({ ...$store, loading: true }))
|
|
||||||
const page = await fetchPage(state.bookmarks[state.pageNumber + 1])
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
store.update($store => {
|
|
||||||
let { bookmarks, pageNumber } = $store
|
|
||||||
if (page.hasNextPage) {
|
|
||||||
bookmarks[pageNumber + 2] = page.bookmark
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...$store,
|
|
||||||
pageNumber: pageNumber + 1,
|
|
||||||
rows: page.rows,
|
|
||||||
bookmarks,
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the previous page of data
|
|
||||||
const prevPage = async () => {
|
|
||||||
const state = get(derivedStore)
|
|
||||||
if (state.loading || !options.paginate || !state.hasPrevPage) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch previous page
|
|
||||||
store.update($store => ({ ...$store, loading: true }))
|
|
||||||
const page = await fetchPage(state.bookmarks[state.pageNumber - 1])
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
store.update($store => {
|
|
||||||
return {
|
|
||||||
...$store,
|
|
||||||
pageNumber: $store.pageNumber - 1,
|
|
||||||
rows: page.rows,
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets the data set and updates options
|
|
||||||
const update = async newOptions => {
|
|
||||||
if (newOptions) {
|
|
||||||
options = {
|
|
||||||
...options,
|
|
||||||
...newOptions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await fetchData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loads the same page again
|
|
||||||
const refresh = async () => {
|
|
||||||
if (get(store).loading) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const page = await fetchPage(lastBookmark)
|
|
||||||
store.update($store => ({ ...$store, rows: page.rows }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initially fetch data but don't bother waiting for the result
|
|
||||||
fetchData()
|
|
||||||
|
|
||||||
// Return our derived store which will be updated over time
|
|
||||||
return {
|
|
||||||
subscribe: derivedStore.subscribe,
|
|
||||||
nextPage,
|
|
||||||
prevPage,
|
|
||||||
update,
|
|
||||||
refresh,
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue