Broadcast datasource change via websocket when making changes to tables
This commit is contained in:
parent
4ea5b69ed3
commit
5e5dc902d1
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
ctx,
|
||||||
|
ctx.appId,
|
||||||
|
BuilderSocketEvent.TableChange,
|
||||||
|
{
|
||||||
id: table._id,
|
id: table._id,
|
||||||
table,
|
table,
|
||||||
})
|
},
|
||||||
gridSocket?.emitTableUpdate(ctx, 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(
|
||||||
|
ctx,
|
||||||
|
ctx.appId,
|
||||||
|
BuilderSocketEvent.TableChange,
|
||||||
|
{
|
||||||
id,
|
id,
|
||||||
table: null,
|
table: null,
|
||||||
})
|
},
|
||||||
gridSocket?.emitTableDeletion(ctx, id)
|
options
|
||||||
|
)
|
||||||
|
gridSocket?.emitTableDeletion(ctx, id, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitDatasourceUpdate(ctx: any, datasource: Datasource) {
|
emitDatasourceUpdate(
|
||||||
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.DatasourceChange, {
|
ctx: any,
|
||||||
|
datasource: Datasource,
|
||||||
|
options?: SocketMessageOptions
|
||||||
|
) {
|
||||||
|
this.emitToRoom(
|
||||||
|
ctx,
|
||||||
|
ctx.appId,
|
||||||
|
BuilderSocketEvent.DatasourceChange,
|
||||||
|
{
|
||||||
id: datasource._id,
|
id: datasource._id,
|
||||||
datasource,
|
datasource,
|
||||||
})
|
},
|
||||||
|
options
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitDatasourceDeletion(ctx: any, id: string) {
|
emitDatasourceDeletion(ctx: any, id: string, options?: SocketMessageOptions) {
|
||||||
this.emitToRoom(ctx, ctx.appId, BuilderSocketEvent.DatasourceChange, {
|
this.emitToRoom(
|
||||||
|
ctx,
|
||||||
|
ctx.appId,
|
||||||
|
BuilderSocketEvent.DatasourceChange,
|
||||||
|
{
|
||||||
id,
|
id,
|
||||||
datasource: null,
|
datasource: null,
|
||||||
})
|
},
|
||||||
|
options
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
ctx,
|
||||||
|
tableId,
|
||||||
|
GridSocketEvent.RowChange,
|
||||||
|
{
|
||||||
id: row._id,
|
id: row._id,
|
||||||
row,
|
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(
|
||||||
|
ctx,
|
||||||
|
table._id!,
|
||||||
|
GridSocketEvent.TableChange,
|
||||||
|
{
|
||||||
id: table._id,
|
id: table._id,
|
||||||
table,
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,7 @@ export interface SocketSession {
|
||||||
room?: string
|
room?: string
|
||||||
connectedAt: number
|
connectedAt: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SocketMessageOptions {
|
||||||
|
includeOriginator?: boolean
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue