Simplify websocket comms for grid and improve builder socket
This commit is contained in:
parent
0bebacc741
commit
3794d8e204
|
@ -2,7 +2,7 @@ import { getFrontendStore } from "./store/frontend"
|
||||||
import { getAutomationStore } from "./store/automation"
|
import { getAutomationStore } from "./store/automation"
|
||||||
import { getTemporalStore } from "./store/temporal"
|
import { getTemporalStore } from "./store/temporal"
|
||||||
import { getThemeStore } from "./store/theme"
|
import { getThemeStore } from "./store/theme"
|
||||||
import { getUsersStore } from "./store/users"
|
import { getUserStore } from "./store/users"
|
||||||
import { derived } from "svelte/store"
|
import { derived } from "svelte/store"
|
||||||
import { findComponent, findComponentPath } from "./componentUtils"
|
import { findComponent, findComponentPath } from "./componentUtils"
|
||||||
import { RoleUtils } from "@budibase/frontend-core"
|
import { RoleUtils } from "@budibase/frontend-core"
|
||||||
|
@ -13,7 +13,7 @@ export const store = getFrontendStore()
|
||||||
export const automationStore = getAutomationStore()
|
export const automationStore = getAutomationStore()
|
||||||
export const themeStore = getThemeStore()
|
export const themeStore = getThemeStore()
|
||||||
export const temporalStore = getTemporalStore()
|
export const temporalStore = getTemporalStore()
|
||||||
export const usersStore = getUsersStore()
|
export const userStore = getUserStore()
|
||||||
|
|
||||||
// Setup history for screens
|
// Setup history for screens
|
||||||
export const screenHistoryStore = createHistoryStore({
|
export const screenHistoryStore = createHistoryStore({
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
selectedComponent,
|
selectedComponent,
|
||||||
screenHistoryStore,
|
screenHistoryStore,
|
||||||
automationHistoryStore,
|
automationHistoryStore,
|
||||||
|
userStore,
|
||||||
} from "builderStore"
|
} from "builderStore"
|
||||||
import {
|
import {
|
||||||
datasources,
|
datasources,
|
||||||
|
@ -85,9 +86,6 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
// Onboarding
|
// Onboarding
|
||||||
onboarding: false,
|
onboarding: false,
|
||||||
tourNodes: null,
|
tourNodes: null,
|
||||||
|
|
||||||
// Multi user collab
|
|
||||||
users: [],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFrontendStore = () => {
|
export const getFrontendStore = () => {
|
||||||
|
@ -122,7 +120,6 @@ export const getFrontendStore = () => {
|
||||||
initialise: async pkg => {
|
initialise: async pkg => {
|
||||||
const { layouts, screens, application, clientLibPath, hasLock } = pkg
|
const { layouts, screens, application, clientLibPath, hasLock } = pkg
|
||||||
websocket = createBuilderWebsocket()
|
websocket = createBuilderWebsocket()
|
||||||
|
|
||||||
await store.actions.components.refreshDefinitions(application.appId)
|
await store.actions.components.refreshDefinitions(application.appId)
|
||||||
|
|
||||||
// Reset store state
|
// Reset store state
|
||||||
|
|
|
@ -1,10 +1,43 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
|
||||||
export const getUsersStore = () => {
|
export const getUserStore = () => {
|
||||||
const initialValue = {
|
const store = writable([])
|
||||||
users: [],
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import { createWebsocket } from "@budibase/frontend-core"
|
import { createWebsocket } from "@budibase/frontend-core"
|
||||||
import { store } from "builderStore"
|
import { userStore } from "builderStore"
|
||||||
|
|
||||||
export const createBuilderWebsocket = () => {
|
export const createBuilderWebsocket = () => {
|
||||||
const socket = createWebsocket("/socket/builder")
|
const socket = createWebsocket("/socket/builder")
|
||||||
|
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
socket.emit("get-users", null, response => {
|
socket.emit("get-users", null, response => {
|
||||||
console.log("conntected!", response.users)
|
userStore.actions.init(response.users)
|
||||||
store.update(state => ({
|
|
||||||
...state,
|
|
||||||
users: response.users,
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("user-update", user => {})
|
socket.on("user-update", userStore.actions.updateUser)
|
||||||
|
socket.on("user-disconnect", userStore.actions.removeUser)
|
||||||
socket.on("user-disconnect", user => {})
|
|
||||||
|
|
||||||
socket.on("connect_error", err => {
|
socket.on("connect_error", err => {
|
||||||
console.log("Failed to connect to builder websocket:", err.message)
|
console.log("Failed to connect to builder websocket:", err.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
return socket
|
return {
|
||||||
|
...socket,
|
||||||
|
disconnect: () => {
|
||||||
|
socket?.disconnect()
|
||||||
|
userStore.actions.reset()
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
allowDeleteRows={!isUsersTable}
|
allowDeleteRows={!isUsersTable}
|
||||||
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
||||||
on:updatetable={e => tables.updateTable(e.detail)}
|
on:updatetable={e => tables.updateTable(e.detail)}
|
||||||
|
showAvatars={false}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="controls">
|
<svelte:fragment slot="controls">
|
||||||
{#if isInternal}
|
{#if isInternal}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore, userStore } from "builderStore"
|
||||||
import { roles, flags } from "stores/backend"
|
import { roles, flags } from "stores/backend"
|
||||||
import { auth } from "stores/portal"
|
import { auth } from "stores/portal"
|
||||||
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
|
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="toprightnav">
|
<div class="toprightnav">
|
||||||
<UserAvatars users={$store.users} />
|
<UserAvatars users={$userStore} />
|
||||||
<AppActions {application} />
|
<AppActions {application} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
export let allowExpandRows = true
|
export let allowExpandRows = true
|
||||||
export let allowEditRows = true
|
export let allowEditRows = true
|
||||||
export let allowDeleteRows = true
|
export let allowDeleteRows = true
|
||||||
|
export let collaboration = true
|
||||||
|
export let showAvatars = true
|
||||||
|
|
||||||
// Unique identifier for DOM nodes inside this instance
|
// Unique identifier for DOM nodes inside this instance
|
||||||
const rand = Math.random()
|
const rand = Math.random()
|
||||||
|
@ -98,7 +100,11 @@
|
||||||
export const getContext = () => context
|
export const getContext = () => context
|
||||||
|
|
||||||
// Initialise websocket for multi-user
|
// Initialise websocket for multi-user
|
||||||
onMount(() => createGridWebsocket(context))
|
onMount(() => {
|
||||||
|
if (collaboration) {
|
||||||
|
return createGridWebsocket(context)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -119,7 +125,9 @@
|
||||||
<RowHeightButton />
|
<RowHeightButton />
|
||||||
</div>
|
</div>
|
||||||
<div class="controls-right">
|
<div class="controls-right">
|
||||||
<UserAvatars />
|
{#if showAvatars}
|
||||||
|
<UserAvatars />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if $loaded}
|
{#if $loaded}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { get } from "svelte/store"
|
||||||
import { createWebsocket } from "../../../utils"
|
import { createWebsocket } from "../../../utils"
|
||||||
|
|
||||||
export const createGridWebsocket = context => {
|
export const createGridWebsocket = context => {
|
||||||
const { rows, tableId, users, userId, focusedCellId } = context
|
const { rows, tableId, users, focusedCellId } = context
|
||||||
const socket = createWebsocket("/socket/grid")
|
const socket = createWebsocket("/socket/grid")
|
||||||
|
|
||||||
const connectToTable = tableId => {
|
const connectToTable = tableId => {
|
||||||
|
@ -13,7 +13,6 @@ export const createGridWebsocket = context => {
|
||||||
socket.emit("select-table", tableId, response => {
|
socket.emit("select-table", tableId, response => {
|
||||||
// handle initial connection info
|
// handle initial connection info
|
||||||
users.set(response.users)
|
users.set(response.users)
|
||||||
userId.set(response.id)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,56 +2,28 @@ import { writable, get, derived } from "svelte/store"
|
||||||
|
|
||||||
export const createStores = () => {
|
export const createStores = () => {
|
||||||
const users = writable([])
|
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 {
|
return {
|
||||||
users: {
|
users,
|
||||||
...users,
|
|
||||||
subscribe: enrichedUsers.subscribe,
|
|
||||||
},
|
|
||||||
userId,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deriveStores = context => {
|
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
|
// Generate a lookup map of cell ID to the user that has it selected, to make
|
||||||
// lookups inside cells extremely fast
|
// lookups inside cells extremely fast
|
||||||
const selectedCellMap = derived(
|
const selectedCellMap = derived(
|
||||||
[users, userId],
|
[users, focusedCellId],
|
||||||
([$enrichedUsers, $userId]) => {
|
([$users, $focusedCellId]) => {
|
||||||
let map = {}
|
let map = {}
|
||||||
$enrichedUsers.forEach(user => {
|
$users.forEach(user => {
|
||||||
if (user.focusedCellId && user.id !== $userId) {
|
if (user.focusedCellId && user.focusedCellId !== $focusedCellId) {
|
||||||
map[user.focusedCellId] = user
|
map[user.focusedCellId] = user
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return map
|
return map
|
||||||
},
|
}
|
||||||
{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const updateUser = user => {
|
const updateUser = user => {
|
||||||
|
|
|
@ -34,7 +34,6 @@ export default class GridSocket extends Socket {
|
||||||
const sockets = await this.io.in(currentRoom).fetchSockets()
|
const sockets = await this.io.in(currentRoom).fetchSockets()
|
||||||
callback({
|
callback({
|
||||||
users: sockets.map(socket => socket.data.user),
|
users: sockets.map(socket => socket.data.user),
|
||||||
id: user.id,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue