Update grid websocket to send actual changes down to reduce API load
This commit is contained in:
parent
d752448403
commit
f8f970bf7e
6 changed files with 59 additions and 33 deletions
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext } from "svelte"
|
import { setContext, onMount } from "svelte"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { fade } from "svelte/transition"
|
import { fade } from "svelte/transition"
|
||||||
import { clickOutside, ProgressCircle } from "@budibase/bbui"
|
import { clickOutside, ProgressCircle } from "@budibase/bbui"
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
import RowHeightButton from "../controls/RowHeightButton.svelte"
|
import RowHeightButton from "../controls/RowHeightButton.svelte"
|
||||||
import ColumnWidthButton from "../controls/ColumnWidthButton.svelte"
|
import ColumnWidthButton from "../controls/ColumnWidthButton.svelte"
|
||||||
import NewRow from "./NewRow.svelte"
|
import NewRow from "./NewRow.svelte"
|
||||||
|
import { createWebsocket } from "../lib/websocket"
|
||||||
import {
|
import {
|
||||||
MaxCellRenderHeight,
|
MaxCellRenderHeight,
|
||||||
MaxCellRenderWidthOverflow,
|
MaxCellRenderWidthOverflow,
|
||||||
|
@ -97,7 +98,7 @@
|
||||||
export const getContext = () => context
|
export const getContext = () => context
|
||||||
|
|
||||||
// Initialise websocket for multi-user
|
// Initialise websocket for multi-user
|
||||||
// onMount(() => createWebsocket(context))
|
onMount(() => createWebsocket(context))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -38,7 +38,7 @@ export const createWebsocket = context => {
|
||||||
})
|
})
|
||||||
socket.on("row-update", data => {
|
socket.on("row-update", data => {
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
rows.actions.refreshRow(data.id)
|
rows.actions.replaceRow(data.id, data.row)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
socket.on("user-update", user => {
|
socket.on("user-update", user => {
|
||||||
|
|
|
@ -268,27 +268,25 @@ export const deriveStores = context => {
|
||||||
return res?.rows?.[0]
|
return res?.rows?.[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refreshes a specific row, handling updates, addition or deletion
|
// Replaces a row in state with the newly defined row, handling updates,
|
||||||
const refreshRow = async id => {
|
// addition and deletion
|
||||||
// Fetch row from the server again
|
const replaceRow = (id, row) => {
|
||||||
const newRow = await fetchRow(id)
|
|
||||||
|
|
||||||
// Get index of row to check if it exists
|
// Get index of row to check if it exists
|
||||||
const $rows = get(rows)
|
const $rows = get(rows)
|
||||||
const $rowLookupMap = get(rowLookupMap)
|
const $rowLookupMap = get(rowLookupMap)
|
||||||
const index = $rowLookupMap[id]
|
const index = $rowLookupMap[id]
|
||||||
|
|
||||||
// Process as either an update, addition or deletion
|
// Process as either an update, addition or deletion
|
||||||
if (newRow) {
|
if (row) {
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
// An existing row was updated
|
// An existing row was updated
|
||||||
rows.update(state => {
|
rows.update(state => {
|
||||||
state[index] = { ...newRow }
|
state[index] = { ...row }
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// A new row was created
|
// A new row was created
|
||||||
handleNewRows([newRow])
|
handleNewRows([row])
|
||||||
}
|
}
|
||||||
} else if (index != null) {
|
} else if (index != null) {
|
||||||
// A row was removed
|
// A row was removed
|
||||||
|
@ -296,6 +294,15 @@ export const deriveStores = context => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refreshes a specific row
|
||||||
|
const refreshRow = async id => {
|
||||||
|
// Fetch row from the server again
|
||||||
|
const row = await fetchRow(id)
|
||||||
|
|
||||||
|
// Update local state
|
||||||
|
replaceRow(id, row)
|
||||||
|
}
|
||||||
|
|
||||||
// Refreshes all data
|
// Refreshes all data
|
||||||
const refreshData = () => {
|
const refreshData = () => {
|
||||||
get(fetch)?.getInitialData()
|
get(fetch)?.getInitialData()
|
||||||
|
@ -455,6 +462,7 @@ export const deriveStores = context => {
|
||||||
hasRow,
|
hasRow,
|
||||||
loadNextPage,
|
loadNextPage,
|
||||||
refreshRow,
|
refreshRow,
|
||||||
|
replaceRow,
|
||||||
refreshData,
|
refreshData,
|
||||||
refreshTableDefinition,
|
refreshTableDefinition,
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as external from "./external"
|
||||||
import { isExternalTable } from "../../../integrations/utils"
|
import { isExternalTable } from "../../../integrations/utils"
|
||||||
import { Ctx } from "@budibase/types"
|
import { Ctx } from "@budibase/types"
|
||||||
import * as utils from "./utils"
|
import * as utils from "./utils"
|
||||||
|
import { gridSocket } from "../../../websockets"
|
||||||
|
|
||||||
function pickApi(tableId: any) {
|
function pickApi(tableId: any) {
|
||||||
if (isExternalTable(tableId)) {
|
if (isExternalTable(tableId)) {
|
||||||
|
@ -12,21 +13,9 @@ function pickApi(tableId: any) {
|
||||||
return internal
|
return internal
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTableId(ctx: any) {
|
|
||||||
if (ctx.request.body && ctx.request.body.tableId) {
|
|
||||||
return ctx.request.body.tableId
|
|
||||||
}
|
|
||||||
if (ctx.params && ctx.params.tableId) {
|
|
||||||
return ctx.params.tableId
|
|
||||||
}
|
|
||||||
if (ctx.params && ctx.params.viewName) {
|
|
||||||
return ctx.params.viewName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function patch(ctx: any): Promise<any> {
|
export async function patch(ctx: any): Promise<any> {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
const body = ctx.request.body
|
const body = ctx.request.body
|
||||||
// if it doesn't have an _id then its save
|
// if it doesn't have an _id then its save
|
||||||
if (body && !body._id) {
|
if (body && !body._id) {
|
||||||
|
@ -47,6 +36,7 @@ export async function patch(ctx: any): Promise<any> {
|
||||||
ctx.eventEmitter.emitRow(`row:update`, appId, row, table)
|
ctx.eventEmitter.emitRow(`row:update`, appId, row, table)
|
||||||
ctx.message = `${table.name} updated successfully.`
|
ctx.message = `${table.name} updated successfully.`
|
||||||
ctx.body = row
|
ctx.body = row
|
||||||
|
gridSocket?.emitRowUpdate(ctx, row)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ctx.throw(400, err)
|
ctx.throw(400, err)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +44,7 @@ export async function patch(ctx: any): Promise<any> {
|
||||||
|
|
||||||
export const save = async (ctx: any) => {
|
export const save = async (ctx: any) => {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
const body = ctx.request.body
|
const body = ctx.request.body
|
||||||
// if it has an ID already then its a patch
|
// if it has an ID already then its a patch
|
||||||
if (body && body._id) {
|
if (body && body._id) {
|
||||||
|
@ -69,23 +59,24 @@ export const save = async (ctx: any) => {
|
||||||
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:save`, appId, row, table)
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:save`, appId, row, table)
|
||||||
ctx.message = `${table.name} saved successfully`
|
ctx.message = `${table.name} saved successfully`
|
||||||
ctx.body = row
|
ctx.body = row
|
||||||
|
gridSocket?.emitRowUpdate(ctx, row)
|
||||||
}
|
}
|
||||||
export async function fetchView(ctx: any) {
|
export async function fetchView(ctx: any) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await quotas.addQuery(() => pickApi(tableId).fetchView(ctx), {
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).fetchView(ctx), {
|
||||||
datasourceId: tableId,
|
datasourceId: tableId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetch(ctx: any) {
|
export async function fetch(ctx: any) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await quotas.addQuery(() => pickApi(tableId).fetch(ctx), {
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).fetch(ctx), {
|
||||||
datasourceId: tableId,
|
datasourceId: tableId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function find(ctx: any) {
|
export async function find(ctx: any) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await quotas.addQuery(() => pickApi(tableId).find(ctx), {
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).find(ctx), {
|
||||||
datasourceId: tableId,
|
datasourceId: tableId,
|
||||||
})
|
})
|
||||||
|
@ -94,7 +85,7 @@ export async function find(ctx: any) {
|
||||||
export async function destroy(ctx: any) {
|
export async function destroy(ctx: any) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const inputs = ctx.request.body
|
const inputs = ctx.request.body
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
let response, row
|
let response, row
|
||||||
if (inputs.rows) {
|
if (inputs.rows) {
|
||||||
let { rows } = await quotas.addQuery(
|
let { rows } = await quotas.addQuery(
|
||||||
|
@ -107,6 +98,7 @@ export async function destroy(ctx: any) {
|
||||||
response = rows
|
response = rows
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
||||||
|
gridSocket?.emitRowDeletion(ctx, row._id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), {
|
let resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), {
|
||||||
|
@ -116,6 +108,7 @@ export async function destroy(ctx: any) {
|
||||||
response = resp.response
|
response = resp.response
|
||||||
row = resp.row
|
row = resp.row
|
||||||
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
||||||
|
gridSocket?.emitRowDeletion(ctx, row._id)
|
||||||
}
|
}
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
// for automations include the row that was deleted
|
// for automations include the row that was deleted
|
||||||
|
@ -124,7 +117,7 @@ export async function destroy(ctx: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: any) {
|
export async function search(ctx: any) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
ctx.body = await quotas.addQuery(() => pickApi(tableId).search(ctx), {
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).search(ctx), {
|
||||||
datasourceId: tableId,
|
datasourceId: tableId,
|
||||||
|
@ -132,7 +125,7 @@ export async function search(ctx: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function validate(ctx: Ctx) {
|
export async function validate(ctx: Ctx) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
// external tables are hard to validate currently
|
// external tables are hard to validate currently
|
||||||
if (isExternalTable(tableId)) {
|
if (isExternalTable(tableId)) {
|
||||||
ctx.body = { valid: true }
|
ctx.body = { valid: true }
|
||||||
|
@ -145,7 +138,7 @@ export async function validate(ctx: Ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchEnrichedRow(ctx: any) {
|
export async function fetchEnrichedRow(ctx: any) {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await quotas.addQuery(
|
ctx.body = await quotas.addQuery(
|
||||||
() => pickApi(tableId).fetchEnrichedRow(ctx),
|
() => pickApi(tableId).fetchEnrichedRow(ctx),
|
||||||
{
|
{
|
||||||
|
@ -155,7 +148,7 @@ export async function fetchEnrichedRow(ctx: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const exportRows = async (ctx: any) => {
|
export const exportRows = async (ctx: any) => {
|
||||||
const tableId = getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
ctx.body = await quotas.addQuery(() => pickApi(tableId).exportRows(ctx), {
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).exportRows(ctx), {
|
||||||
datasourceId: tableId,
|
datasourceId: tableId,
|
||||||
})
|
})
|
||||||
|
|
|
@ -154,3 +154,15 @@ export function cleanExportRows(
|
||||||
|
|
||||||
return cleanRows
|
return cleanRows
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTableId(ctx: any) {
|
||||||
|
if (ctx.request.body && ctx.request.body.tableId) {
|
||||||
|
return ctx.request.body.tableId
|
||||||
|
}
|
||||||
|
if (ctx.params && ctx.params.tableId) {
|
||||||
|
return ctx.params.tableId
|
||||||
|
}
|
||||||
|
if (ctx.params && ctx.params.viewName) {
|
||||||
|
return ctx.params.viewName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ import Socket from "./websocket"
|
||||||
import { permissions } from "@budibase/backend-core"
|
import { permissions } from "@budibase/backend-core"
|
||||||
import http from "http"
|
import http from "http"
|
||||||
import Koa from "koa"
|
import Koa from "koa"
|
||||||
|
import { getTableId } from "../api/controllers/row/utils"
|
||||||
|
import { Row } from "@budibase/types"
|
||||||
|
|
||||||
export default class GridSocket extends Socket {
|
export default class GridSocket extends Socket {
|
||||||
constructor(app: Koa, server: http.Server) {
|
constructor(app: Koa, server: http.Server) {
|
||||||
|
@ -52,4 +54,14 @@ export default class GridSocket extends Socket {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitRowUpdate(ctx: any, row: Row) {
|
||||||
|
const tableId = getTableId(ctx)
|
||||||
|
this.io.in(tableId).emit("row-update", { id: row._id, row })
|
||||||
|
}
|
||||||
|
|
||||||
|
emitRowDeletion(ctx: any, id: string) {
|
||||||
|
const tableId = getTableId(ctx)
|
||||||
|
this.io.in(tableId).emit("row-update", { id, row: null })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue