Update server and builder to properly sync changes with tables and views across all users

This commit is contained in:
Andrew Kingston 2023-08-17 16:04:56 +01:00
parent 733a638a99
commit b5546f8d9b
8 changed files with 61 additions and 25 deletions

View File

@ -3,7 +3,7 @@ import { createWebsocket } from "../../../utils"
import { SocketEvent, GridSocketEvent } from "@budibase/shared-core"
export const createGridWebsocket = context => {
const { rows, datasource, users, focusedCellId, table, API } = context
const { rows, datasource, users, focusedCellId, definition, API } = context
const socket = createWebsocket("/socket/grid")
const connectToDatasource = datasource => {
@ -51,13 +51,16 @@ export const createGridWebsocket = context => {
})
// Table events
socket.onOther(GridSocketEvent.TableChange, ({ table: newTable }) => {
// Only update table if one exists. If the table was deleted then we don't
// want to know - let the builder navigate away
if (newTable) {
table.set(newTable)
socket.onOther(
GridSocketEvent.DatasourceChange,
({ datasource: newDatasource }) => {
// Only update definition if one exists. If the datasource was deleted
// then we don't want to know - let the builder navigate away
if (newDatasource) {
definition.set(newDatasource)
}
}
})
)
// Change websocket connection when table changes
datasource.subscribe(connectToDatasource)

View File

@ -159,7 +159,7 @@ async function deleteRows(ctx: UserCtx<DeleteRowRequest>) {
for (let row of rows) {
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
gridSocket?.emitRowDeletion(ctx, row._id!)
gridSocket?.emitRowDeletion(ctx, row)
}
return rows
@ -175,7 +175,7 @@ async function deleteRow(ctx: UserCtx<DeleteRowRequest>) {
await quotas.removeRow()
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, resp.row)
gridSocket?.emitRowDeletion(ctx, resp.row._id!)
gridSocket?.emitRowDeletion(ctx, resp.row)
return resp
}

View File

@ -93,7 +93,7 @@ export async function destroy(ctx: UserCtx) {
ctx.status = 200
ctx.table = deletedTable
ctx.body = { message: `Table ${tableId} deleted.` }
builderSocket?.emitTableDeletion(ctx, tableId)
builderSocket?.emitTableDeletion(ctx, deletedTable)
}
export async function bulkImport(ctx: UserCtx) {

View File

@ -8,7 +8,7 @@ import {
ViewResponse,
ViewV2,
} from "@budibase/types"
import { builderSocket } from "../../../websockets"
import { builderSocket, gridSocket } from "../../../websockets"
async function parseSchema(view: CreateViewRequest) {
if (!view.schema) {
@ -41,7 +41,7 @@ async function parseSchema(view: CreateViewRequest) {
export async function get(ctx: Ctx<void, ViewResponse>) {
ctx.body = {
data: await sdk.views.get(ctx.params.viewId, { enriched: true })
data: await sdk.views.get(ctx.params.viewId, { enriched: true }),
}
}
@ -67,6 +67,7 @@ export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
const table = await sdk.tables.getTable(tableId)
builderSocket?.emitTableUpdate(ctx, table)
gridSocket?.emitViewUpdate(ctx, result)
}
export async function update(ctx: Ctx<UpdateViewRequest, ViewResponse>) {
@ -101,6 +102,7 @@ export async function update(ctx: Ctx<UpdateViewRequest, ViewResponse>) {
const table = await sdk.tables.getTable(tableId)
builderSocket?.emitTableUpdate(ctx, table)
gridSocket?.emitViewUpdate(ctx, result)
}
export async function remove(ctx: Ctx) {
@ -111,4 +113,5 @@ export async function remove(ctx: Ctx) {
const table = await sdk.tables.getTable(view.tableId)
builderSocket?.emitTableUpdate(ctx, table)
gridSocket?.emitViewDeletion(ctx, view)
}

View File

@ -108,12 +108,12 @@ export default class BuilderSocket extends BaseSocket {
gridSocket?.emitTableUpdate(ctx, table)
}
emitTableDeletion(ctx: any, id: string) {
emitTableDeletion(ctx: any, table: Table) {
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.TableChange, {
id,
id: table._id,
table: null,
})
gridSocket?.emitTableDeletion(ctx, id)
gridSocket?.emitTableDeletion(ctx, table)
}
emitDatasourceUpdate(ctx: any, datasource: Datasource) {

View File

@ -5,7 +5,7 @@ import { auth, permissions } from "@budibase/backend-core"
import http from "http"
import Koa from "koa"
import { getTableId } from "../api/controllers/row/utils"
import { Row, Table } from "@budibase/types"
import { Row, Table, View, ViewV2 } from "@budibase/types"
import { Socket } from "socket.io"
import { GridSocketEvent } from "@budibase/shared-core"
import { userAgent } from "koa-useragent"
@ -88,22 +88,52 @@ export default class GridSocket extends BaseSocket {
})
}
emitRowDeletion(ctx: any, id: string) {
emitRowDeletion(ctx: any, row: Row) {
const resourceId = ctx.params?.viewId || getTableId(ctx)
const room = `${ctx.appId}-${resourceId}`
this.emitToRoom(ctx, room, GridSocketEvent.RowChange, { id, row: null })
this.emitToRoom(ctx, room, GridSocketEvent.RowChange, {
id: row._id,
row: null,
})
}
emitTableUpdate(ctx: any, table: Table) {
const room = `${ctx.appId}-${table._id}`
this.emitToRoom(ctx, room, GridSocketEvent.TableChange, {
this.emitToRoom(ctx, room, GridSocketEvent.DatasourceChange, {
id: table._id,
table,
datasource: table,
})
}
emitTableDeletion(ctx: any, id: string) {
const room = `${ctx.appId}-${id}`
this.emitToRoom(ctx, room, GridSocketEvent.TableChange, { id, table: null })
emitTableDeletion(ctx: any, table: Table) {
const room = `${ctx.appId}-${table._id}`
this.emitToRoom(ctx, room, GridSocketEvent.DatasourceChange, {
id: table._id,
datasource: null,
})
// When the table is deleted we need to notify all views that they have
// also been deleted
Object.values(table.views || {})
.filter((view: View | ViewV2) => (view as ViewV2).version === 2)
.forEach((view: View | ViewV2) => {
this.emitViewDeletion(ctx, view as ViewV2)
})
}
emitViewUpdate(ctx: any, view: ViewV2) {
const room = `${ctx.appId}-${view.id}`
this.emitToRoom(ctx, room, GridSocketEvent.DatasourceChange, {
id: view.id,
datasource: view,
})
}
emitViewDeletion(ctx: any, view: ViewV2) {
const room = `${ctx.appId}-${view.id}`
this.emitToRoom(ctx, room, GridSocketEvent.DatasourceChange, {
id: view.id,
datasource: null,
})
}
}

View File

@ -270,7 +270,7 @@ export class BaseSocket {
// Emit an event to everyone in a room, including metadata of whom
// the originator of the request was
emitToRoom(ctx: any, room: string, event: string, payload: any) {
emitToRoom(ctx: any, room: string | string[], event: string, payload: any) {
this.io.in(room).emit(event, {
...payload,
apiSessionId: ctx.headers?.[Header.SESSION_ID],

View File

@ -76,7 +76,7 @@ export enum SocketEvent {
export enum GridSocketEvent {
RowChange = "RowChange",
TableChange = "TableChange",
DatasourceChange = "DatasourceChange",
SelectDatasource = "SelectDatasource",
SelectCell = "SelectCell",
}