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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import { auth, 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 { 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 { Socket } from "socket.io"
import { GridSocketEvent } from "@budibase/shared-core" import { GridSocketEvent } from "@budibase/shared-core"
import { userAgent } from "koa-useragent" 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 resourceId = ctx.params?.viewId || getTableId(ctx)
const room = `${ctx.appId}-${resourceId}` 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) { emitTableUpdate(ctx: any, table: Table) {
const room = `${ctx.appId}-${table._id}` const room = `${ctx.appId}-${table._id}`
this.emitToRoom(ctx, room, GridSocketEvent.TableChange, { this.emitToRoom(ctx, room, GridSocketEvent.DatasourceChange, {
id: table._id, id: table._id,
table, datasource: table,
}) })
} }
emitTableDeletion(ctx: any, id: string) { emitTableDeletion(ctx: any, table: Table) {
const room = `${ctx.appId}-${id}` const room = `${ctx.appId}-${table._id}`
this.emitToRoom(ctx, room, GridSocketEvent.TableChange, { id, table: null }) 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 // Emit an event to everyone in a room, including metadata of whom
// the originator of the request was // 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, { this.io.in(room).emit(event, {
...payload, ...payload,
apiSessionId: ctx.headers?.[Header.SESSION_ID], apiSessionId: ctx.headers?.[Header.SESSION_ID],

View File

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