Merge pull request #8066 from Budibase/plugin-improvements-master
Plugin fixes and improvements
This commit is contained in:
commit
4e20c979ff
|
@ -143,7 +143,10 @@ export const getComponentSettings = componentType => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure whole component name is used
|
// Ensure whole component name is used
|
||||||
if (!componentType.startsWith("@budibase")) {
|
if (
|
||||||
|
!componentType.startsWith("plugin/") &&
|
||||||
|
!componentType.startsWith("@budibase")
|
||||||
|
) {
|
||||||
componentType = `@budibase/standard-components/${componentType}`
|
componentType = `@budibase/standard-components/${componentType}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,18 +243,18 @@ export const getDatasourceForProvider = (asset, component) => {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are different types of setting which can be a datasource, for
|
// For legacy compatibility, we need to be able to handle datasources that are
|
||||||
// example an actual datasource object, or a table ID string.
|
// just strings. These are not generated any more, so could be removed in
|
||||||
// Convert the datasource setting into a proper datasource object so that
|
// future.
|
||||||
// we can use it properly
|
// TODO: remove at some point
|
||||||
if (datasourceSetting.type === "table") {
|
const datasource = component[datasourceSetting?.key]
|
||||||
|
if (typeof datasource === "string") {
|
||||||
return {
|
return {
|
||||||
tableId: component[datasourceSetting?.key],
|
tableId: datasource,
|
||||||
type: "table",
|
type: "table",
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return component[datasourceSetting?.key]
|
|
||||||
}
|
}
|
||||||
|
return datasource
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -88,27 +88,12 @@ export const getFrontendStore = () => {
|
||||||
initialise: async pkg => {
|
initialise: async pkg => {
|
||||||
const { layouts, screens, application, clientLibPath } = pkg
|
const { layouts, screens, application, clientLibPath } = pkg
|
||||||
|
|
||||||
// Fetch component definitions.
|
await store.actions.components.refreshDefinitions(application.appId)
|
||||||
// Allow errors to propagate.
|
|
||||||
const components = await API.fetchComponentLibDefinitions(
|
|
||||||
application.appId
|
|
||||||
)
|
|
||||||
|
|
||||||
// Filter out custom component keys so we can flag them
|
|
||||||
const customComponents = Object.keys(components).filter(name =>
|
|
||||||
name.startsWith("plugin/")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reset store state
|
// Reset store state
|
||||||
store.update(state => ({
|
store.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
libraries: application.componentLibraries,
|
libraries: application.componentLibraries,
|
||||||
components,
|
|
||||||
customComponents,
|
|
||||||
clientFeatures: {
|
|
||||||
...INITIAL_FRONTEND_STATE.clientFeatures,
|
|
||||||
...components.features,
|
|
||||||
},
|
|
||||||
name: application.name,
|
name: application.name,
|
||||||
description: application.description,
|
description: application.description,
|
||||||
appId: application.appId,
|
appId: application.appId,
|
||||||
|
@ -385,6 +370,29 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
refreshDefinitions: async appId => {
|
||||||
|
if (!appId) {
|
||||||
|
appId = get(store).appId
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch definitions and filter out custom component definitions so we
|
||||||
|
// can flag them
|
||||||
|
const components = await API.fetchComponentLibDefinitions(appId)
|
||||||
|
const customComponents = Object.keys(components).filter(name =>
|
||||||
|
name.startsWith("plugin/")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update store
|
||||||
|
store.update(state => ({
|
||||||
|
...state,
|
||||||
|
components,
|
||||||
|
customComponents,
|
||||||
|
clientFeatures: {
|
||||||
|
...INITIAL_FRONTEND_STATE.clientFeatures,
|
||||||
|
...components.features,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
},
|
||||||
getDefinition: componentName => {
|
getDefinition: componentName => {
|
||||||
if (!componentName) {
|
if (!componentName) {
|
||||||
return null
|
return null
|
||||||
|
@ -428,7 +436,7 @@ export const getFrontendStore = () => {
|
||||||
_id: Helpers.uuid(),
|
_id: Helpers.uuid(),
|
||||||
_component: definition.component,
|
_component: definition.component,
|
||||||
_styles: { normal: {}, hover: {}, active: {} },
|
_styles: { normal: {}, hover: {}, active: {} },
|
||||||
_instanceName: `New ${definition.name}`,
|
_instanceName: `New ${definition.friendlyName || definition.name}`,
|
||||||
...cloneDeep(props),
|
...cloneDeep(props),
|
||||||
...extras,
|
...extras,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
<script>
|
<script>
|
||||||
import { Select } from "@budibase/bbui"
|
import { Select } from "@budibase/bbui"
|
||||||
import { tables } from "stores/backend"
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { tables as tablesStore } from "stores/backend"
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
$: tables = $tablesStore.list.map(m => ({
|
||||||
|
label: m.name,
|
||||||
|
tableId: m._id,
|
||||||
|
type: "table",
|
||||||
|
}))
|
||||||
|
|
||||||
|
const onChange = e => {
|
||||||
|
const dataSource = tables?.find(x => x.tableId === e.detail)
|
||||||
|
dispatch("change", dataSource)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<Select
|
||||||
<Select extraThin secondary wide on:change {value}>
|
on:change={onChange}
|
||||||
<option value="">Choose a table</option>
|
value={value?.tableId}
|
||||||
{#each $tables.list as table}
|
options={tables}
|
||||||
<option value={table._id}>{table.name}</option>
|
getOptionValue={x => x.tableId}
|
||||||
{/each}
|
getOptionLabel={x => x.label}
|
||||||
</Select>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
div :global(> *) {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -198,6 +198,8 @@
|
||||||
block: "center",
|
block: "center",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
} else if (type === "reload-plugin") {
|
||||||
|
await store.actions.components.refreshDefinitions()
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Client sent unknown event type: ${type}`)
|
console.warn(`Client sent unknown event type: ${type}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,9 @@ const createBuilderStore = () => {
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify the builder so we can reload component definitions
|
||||||
|
dispatchEvent("reload-plugin")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
import { builderStore, environmentStore } from "./stores/index.js"
|
import {
|
||||||
|
builderStore,
|
||||||
|
environmentStore,
|
||||||
|
notificationStore,
|
||||||
|
} from "./stores/index.js"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { io } from "socket.io-client"
|
import { io } from "socket.io-client"
|
||||||
|
|
||||||
|
let socket
|
||||||
|
|
||||||
export const initWebsocket = () => {
|
export const initWebsocket = () => {
|
||||||
const { inBuilder, location } = get(builderStore)
|
const { inBuilder, location } = get(builderStore)
|
||||||
const { cloud } = get(environmentStore)
|
const { cloud } = get(environmentStore)
|
||||||
|
|
||||||
// Only connect when we're inside the builder preview, for now
|
// Only connect when we're inside the builder preview, for now
|
||||||
if (!inBuilder || !location || cloud) {
|
if (!inBuilder || !location || cloud || socket) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,20 +22,20 @@ export const initWebsocket = () => {
|
||||||
const proto = tls ? "wss:" : "ws:"
|
const proto = tls ? "wss:" : "ws:"
|
||||||
const host = location.hostname
|
const host = location.hostname
|
||||||
const port = location.port || (tls ? 443 : 80)
|
const port = location.port || (tls ? 443 : 80)
|
||||||
const socket = io(`${proto}//${host}:${port}`, {
|
socket = io(`${proto}//${host}:${port}`, {
|
||||||
path: "/socket/client",
|
path: "/socket/client",
|
||||||
// Cap reconnection attempts to 10 (total of 95 seconds before giving up)
|
// Cap reconnection attempts to 3 (total of 15 seconds before giving up)
|
||||||
reconnectionAttempts: 10,
|
reconnectionAttempts: 3,
|
||||||
// Delay initial reconnection attempt by 5 seconds
|
// Delay reconnection attempt by 5 seconds
|
||||||
reconnectionDelay: 5000,
|
reconnectionDelay: 5000,
|
||||||
// Then decrease to 10 second intervals
|
reconnectionDelayMax: 5000,
|
||||||
reconnectionDelayMax: 10000,
|
// Timeout after 4 seconds so we never stack requests
|
||||||
// Timeout after 5 seconds so we never stack requests
|
timeout: 4000,
|
||||||
timeout: 5000,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
socket.on("plugin-update", data => {
|
socket.on("plugin-update", data => {
|
||||||
builderStore.actions.updateUsedPlugin(data.name, data.hash)
|
builderStore.actions.updateUsedPlugin(data.name, data.hash)
|
||||||
|
notificationStore.actions.info(`"${data.name}" plugin reloaded`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,9 @@ export const buildRowEndpoints = API => ({
|
||||||
if (!tableId || !rowId) {
|
if (!tableId || !rowId) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const row = await API.get({
|
return await API.get({
|
||||||
url: `/api/${tableId}/rows/${rowId}`,
|
url: `/api/${tableId}/rows/${rowId}`,
|
||||||
})
|
})
|
||||||
return (await API.enrichRows([row], tableId))[0]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue