Simplify websocket comms for grid and improve builder socket

This commit is contained in:
Andrew Kingston 2023-05-18 08:57:20 +01:00
parent 0bebacc741
commit 3794d8e204
10 changed files with 74 additions and 65 deletions

View File

@ -2,7 +2,7 @@ import { getFrontendStore } from "./store/frontend"
import { getAutomationStore } from "./store/automation"
import { getTemporalStore } from "./store/temporal"
import { getThemeStore } from "./store/theme"
import { getUsersStore } from "./store/users"
import { getUserStore } from "./store/users"
import { derived } from "svelte/store"
import { findComponent, findComponentPath } from "./componentUtils"
import { RoleUtils } from "@budibase/frontend-core"
@ -13,7 +13,7 @@ export const store = getFrontendStore()
export const automationStore = getAutomationStore()
export const themeStore = getThemeStore()
export const temporalStore = getTemporalStore()
export const usersStore = getUsersStore()
export const userStore = getUserStore()
// Setup history for screens
export const screenHistoryStore = createHistoryStore({

View File

@ -5,6 +5,7 @@ import {
selectedComponent,
screenHistoryStore,
automationHistoryStore,
userStore,
} from "builderStore"
import {
datasources,
@ -85,9 +86,6 @@ const INITIAL_FRONTEND_STATE = {
// Onboarding
onboarding: false,
tourNodes: null,
// Multi user collab
users: [],
}
export const getFrontendStore = () => {
@ -122,7 +120,6 @@ export const getFrontendStore = () => {
initialise: async pkg => {
const { layouts, screens, application, clientLibPath, hasLock } = pkg
websocket = createBuilderWebsocket()
await store.actions.components.refreshDefinitions(application.appId)
// Reset store state

View File

@ -1,10 +1,43 @@
import { writable } from "svelte/store"
import { writable, get } from "svelte/store"
export const getUsersStore = () => {
const initialValue = {
users: [],
export const getUserStore = () => {
const store = writable([])
const init = users => {
store.set(users)
}
const store = writable(initialValue)
return store
const updateUser = user => {
console.log(user)
const $users = get(store)
if (!$users.some(x => x.id === user.id)) {
store.set([...$users, user])
} else {
store.update(state => {
const index = state.findIndex(x => x.id === user.id)
state[index] = user
return state.slice()
})
}
}
const removeUser = user => {
store.update(state => {
return state.filter(x => x.id !== user.id)
})
}
const reset = () => {
store.set([])
}
return {
...store,
actions: {
init,
updateUser,
removeUser,
reset,
},
}
}

View File

@ -1,26 +1,26 @@
import { createWebsocket } from "@budibase/frontend-core"
import { store } from "builderStore"
import { userStore } from "builderStore"
export const createBuilderWebsocket = () => {
const socket = createWebsocket("/socket/builder")
socket.on("connect", () => {
socket.emit("get-users", null, response => {
console.log("conntected!", response.users)
store.update(state => ({
...state,
users: response.users,
}))
userStore.actions.init(response.users)
})
})
socket.on("user-update", user => {})
socket.on("user-disconnect", user => {})
socket.on("user-update", userStore.actions.updateUser)
socket.on("user-disconnect", userStore.actions.removeUser)
socket.on("connect_error", err => {
console.log("Failed to connect to builder websocket:", err.message)
})
return socket
return {
...socket,
disconnect: () => {
socket?.disconnect()
userStore.actions.reset()
},
}
}

View File

@ -36,6 +36,7 @@
allowDeleteRows={!isUsersTable}
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
on:updatetable={e => tables.updateTable(e.detail)}
showAvatars={false}
>
<svelte:fragment slot="controls">
{#if isInternal}

View File

@ -1,5 +1,5 @@
<script>
import { store, automationStore } from "builderStore"
import { store, automationStore, userStore } from "builderStore"
import { roles, flags } from "stores/backend"
import { auth } from "stores/portal"
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
@ -209,7 +209,7 @@
{/if}
</div>
<div class="toprightnav">
<UserAvatars users={$store.users} />
<UserAvatars users={$userStore} />
<AppActions {application} />
</div>
{/if}

View File

@ -41,6 +41,8 @@
export let allowExpandRows = true
export let allowEditRows = true
export let allowDeleteRows = true
export let collaboration = true
export let showAvatars = true
// Unique identifier for DOM nodes inside this instance
const rand = Math.random()
@ -98,7 +100,11 @@
export const getContext = () => context
// Initialise websocket for multi-user
onMount(() => createGridWebsocket(context))
onMount(() => {
if (collaboration) {
return createGridWebsocket(context)
}
})
</script>
<div
@ -119,7 +125,9 @@
<RowHeightButton />
</div>
<div class="controls-right">
<UserAvatars />
{#if showAvatars}
<UserAvatars />
{/if}
</div>
</div>
{#if $loaded}

View File

@ -2,7 +2,7 @@ import { get } from "svelte/store"
import { createWebsocket } from "../../../utils"
export const createGridWebsocket = context => {
const { rows, tableId, users, userId, focusedCellId } = context
const { rows, tableId, users, focusedCellId } = context
const socket = createWebsocket("/socket/grid")
const connectToTable = tableId => {
@ -13,7 +13,6 @@ export const createGridWebsocket = context => {
socket.emit("select-table", tableId, response => {
// handle initial connection info
users.set(response.users)
userId.set(response.id)
})
}

View File

@ -2,56 +2,28 @@ import { writable, get, derived } from "svelte/store"
export const createStores = () => {
const users = writable([])
const userId = writable(null)
// Enrich users with unique colours
const enrichedUsers = derived(
[users, userId],
([$users, $userId]) => {
return (
$users
.slice()
// Place current user first
.sort((a, b) => {
if (a.id === $userId) {
return -1
} else if (b.id === $userId) {
return 1
} else {
return 0
}
})
)
},
[]
)
return {
users: {
...users,
subscribe: enrichedUsers.subscribe,
},
userId,
users,
}
}
export const deriveStores = context => {
const { users, userId } = context
const { users, focusedCellId } = context
// Generate a lookup map of cell ID to the user that has it selected, to make
// lookups inside cells extremely fast
const selectedCellMap = derived(
[users, userId],
([$enrichedUsers, $userId]) => {
[users, focusedCellId],
([$users, $focusedCellId]) => {
let map = {}
$enrichedUsers.forEach(user => {
if (user.focusedCellId && user.id !== $userId) {
$users.forEach(user => {
if (user.focusedCellId && user.focusedCellId !== $focusedCellId) {
map[user.focusedCellId] = user
}
})
return map
},
{}
}
)
const updateUser = user => {

View File

@ -34,7 +34,6 @@ export default class GridSocket extends Socket {
const sockets = await this.io.in(currentRoom).fetchSockets()
callback({
users: sockets.map(socket => socket.data.user),
id: user.id,
})
})