1
0
Fork 0
mirror of synced 2024-07-30 02:26:11 +12:00

Broadcast datasource change via websocket when making changes to tables

This commit is contained in:
Andrew Kingston 2023-06-15 09:04:21 +01:00
parent 4ea5b69ed3
commit 5e5dc902d1
6 changed files with 125 additions and 45 deletions

View file

@ -1,5 +1,4 @@
import { get, writable, derived } from "svelte/store" import { get, writable, derived } from "svelte/store"
import { datasources } from "./"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { API } from "api" import { API } from "api"
import { SWITCHABLE_TYPES } from "constants/backend" import { SWITCHABLE_TYPES } from "constants/backend"
@ -63,7 +62,6 @@ export function createTablesStore() {
const savedTable = await API.saveTable(updatedTable) const savedTable = await API.saveTable(updatedTable)
replaceTable(savedTable._id, savedTable) replaceTable(savedTable._id, savedTable)
await datasources.fetch()
select(savedTable._id) select(savedTable._id)
return savedTable return savedTable
} }

View file

@ -26,6 +26,7 @@ import {
RelationshipTypes, RelationshipTypes,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { builderSocket } from "../../../websockets"
const { cloneDeep } = require("lodash/fp") const { cloneDeep } = require("lodash/fp")
async function makeTableRequest( async function makeTableRequest(
@ -318,6 +319,13 @@ export async function save(ctx: UserCtx) {
datasource.entities[tableToSave.name] = tableToSave datasource.entities[tableToSave.name] = tableToSave
await db.put(datasource) await db.put(datasource)
// Since tables are stored inside datasources, we need to notify clients
// that the datasource definition changed
const updatedDatasource = await db.get(datasource._id)
builderSocket?.emitDatasourceUpdate(ctx, updatedDatasource, {
includeOriginator: true,
})
return tableToSave return tableToSave
} }

View file

@ -3,7 +3,13 @@ import { BaseSocket } from "./websocket"
import { permissions, events } from "@budibase/backend-core" import { permissions, events } from "@budibase/backend-core"
import http from "http" import http from "http"
import Koa from "koa" import Koa from "koa"
import { Datasource, Table, SocketSession, ContextUser } from "@budibase/types" import {
Datasource,
Table,
SocketSession,
ContextUser,
SocketMessageOptions,
} from "@budibase/types"
import { gridSocket } from "./index" import { gridSocket } from "./index"
import { clearLock, updateLock } from "../utilities/redis" import { clearLock, updateLock } from "../utilities/redis"
import { Socket } from "socket.io" import { Socket } from "socket.io"
@ -66,33 +72,61 @@ export default class BuilderSocket extends BaseSocket {
} }
} }
emitTableUpdate(ctx: any, table: Table) { emitTableUpdate(ctx: any, table: Table, options?: SocketMessageOptions) {
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.TableChange, { this.emitToRoom(
id: table._id, ctx,
table, ctx.appId,
}) BuilderSocketEvent.TableChange,
gridSocket?.emitTableUpdate(ctx, table) {
id: table._id,
table,
},
options
)
gridSocket?.emitTableUpdate(ctx, table, options)
} }
emitTableDeletion(ctx: any, id: string) { emitTableDeletion(ctx: any, id: string, options?: SocketMessageOptions) {
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.TableChange, { this.emitToRoom(
id, ctx,
table: null, ctx.appId,
}) BuilderSocketEvent.TableChange,
gridSocket?.emitTableDeletion(ctx, id) {
id,
table: null,
},
options
)
gridSocket?.emitTableDeletion(ctx, id, options)
} }
emitDatasourceUpdate(ctx: any, datasource: Datasource) { emitDatasourceUpdate(
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.DatasourceChange, { ctx: any,
id: datasource._id, datasource: Datasource,
datasource, options?: SocketMessageOptions
}) ) {
this.emitToRoom(
ctx,
ctx.appId,
BuilderSocketEvent.DatasourceChange,
{
id: datasource._id,
datasource,
},
options
)
} }
emitDatasourceDeletion(ctx: any, id: string) { emitDatasourceDeletion(ctx: any, id: string, options?: SocketMessageOptions) {
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.DatasourceChange, { this.emitToRoom(
id, ctx,
datasource: null, ctx.appId,
}) BuilderSocketEvent.DatasourceChange,
{
id,
datasource: null,
},
options
)
} }
} }

View file

@ -4,7 +4,7 @@ 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 { getTableId } from "../api/controllers/row/utils"
import { Row, Table } from "@budibase/types" import { Row, SocketMessageOptions, Table } 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"
@ -29,27 +29,51 @@ export default class GridSocket extends BaseSocket {
}) })
} }
emitRowUpdate(ctx: any, row: Row) { emitRowUpdate(ctx: any, row: Row, options?: SocketMessageOptions) {
const tableId = getTableId(ctx) const tableId = getTableId(ctx)
this.emitToRoom(ctx, tableId, GridSocketEvent.RowChange, { this.emitToRoom(
id: row._id, ctx,
row, tableId,
}) GridSocketEvent.RowChange,
{
id: row._id,
row,
},
options
)
} }
emitRowDeletion(ctx: any, id: string) { emitRowDeletion(ctx: any, id: string, options?: SocketMessageOptions) {
const tableId = getTableId(ctx) const tableId = getTableId(ctx)
this.emitToRoom(ctx, tableId, GridSocketEvent.RowChange, { id, row: null }) this.emitToRoom(
ctx,
tableId,
GridSocketEvent.RowChange,
{ id, row: null },
options
)
} }
emitTableUpdate(ctx: any, table: Table) { emitTableUpdate(ctx: any, table: Table, options?: SocketMessageOptions) {
this.emitToRoom(ctx, table._id!, GridSocketEvent.TableChange, { this.emitToRoom(
id: table._id, ctx,
table, table._id!,
}) GridSocketEvent.TableChange,
{
id: table._id,
table,
},
options
)
} }
emitTableDeletion(ctx: any, id: string) { emitTableDeletion(ctx: any, id: string, options?: SocketMessageOptions) {
this.emitToRoom(ctx, id, GridSocketEvent.TableChange, { id, table: null }) this.emitToRoom(
ctx,
id,
GridSocketEvent.TableChange,
{ id, table: null },
options
)
} }
} }

View file

@ -9,7 +9,7 @@ import { createAdapter } from "@socket.io/redis-adapter"
import { Socket } from "socket.io" import { Socket } from "socket.io"
import { getSocketPubSubClients } from "../utilities/redis" import { getSocketPubSubClients } from "../utilities/redis"
import { SocketEvent, SocketSessionTTL } from "@budibase/shared-core" import { SocketEvent, SocketSessionTTL } from "@budibase/shared-core"
import { SocketSession } from "@budibase/types" import { SocketSession, SocketMessageOptions } from "@budibase/types"
export class BaseSocket { export class BaseSocket {
io: Server io: Server
@ -276,12 +276,24 @@ export class BaseSocket {
this.io.sockets.emit(event, payload) this.io.sockets.emit(event, payload)
} }
// Emit an event to everyone in a room, including metadata of whom // Emit an event to everyone in a room
// the originator of the request was emitToRoom(
emitToRoom(ctx: any, room: string, event: string, payload: any) { ctx: any,
room: string,
event: string,
payload: any,
options?: SocketMessageOptions
) {
// By default, we include the session API of the originator so that they can ignore
// this event. If we want to include the originator then we leave it unset to that all
// clients will react to it.
let apiSessionId = null
if (!options?.includeOriginator) {
apiSessionId = ctx.headers?.[Header.SESSION_ID]
}
this.io.in(room).emit(event, { this.io.in(room).emit(event, {
...payload, ...payload,
apiSessionId: ctx.headers?.[Header.SESSION_ID], apiSessionId,
}) })
} }
} }

View file

@ -7,3 +7,7 @@ export interface SocketSession {
room?: string room?: string
connectedAt: number connectedAt: number
} }
export interface SocketMessageOptions {
includeOriginator?: boolean
}