Merge pull request #3177 from Budibase/ak-fixes
Relationship aware data provider automatic reloading + extras
This commit is contained in:
commit
97dd8e9989
|
@ -20,7 +20,7 @@ export const executeQuery = async ({ queryId, parameters }) => {
|
||||||
notificationStore.actions.error("An error has occurred")
|
notificationStore.actions.error("An error has occurred")
|
||||||
} else if (!query.readable) {
|
} else if (!query.readable) {
|
||||||
notificationStore.actions.success("Query executed successfully")
|
notificationStore.actions.success("Query executed successfully")
|
||||||
dataSourceStore.actions.invalidateDataSource(query.datasourceId)
|
await dataSourceStore.actions.invalidateDataSource(query.datasourceId)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ export const saveRow = async row => {
|
||||||
: notificationStore.actions.success("Row saved")
|
: notificationStore.actions.success("Row saved")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
await dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ export const updateRow = async row => {
|
||||||
: notificationStore.actions.success("Row updated")
|
: notificationStore.actions.success("Row updated")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
await dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ export const deleteRow = async ({ tableId, rowId, revId }) => {
|
||||||
: notificationStore.actions.success("Row deleted")
|
: notificationStore.actions.success("Row deleted")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(tableId)
|
await dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ export const deleteRows = async ({ tableId, rows }) => {
|
||||||
: notificationStore.actions.success(`${rows.length} row(s) deleted`)
|
: notificationStore.actions.success(`${rows.length} row(s) deleted`)
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
dataSourceStore.actions.invalidateDataSource(tableId)
|
await dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
// Register field with form
|
// Register field with form
|
||||||
const formApi = formContext?.formApi
|
const formApi = formContext?.formApi
|
||||||
const labelPosition = fieldGroupContext?.labelPosition || "above"
|
const labelPos = fieldGroupContext?.labelPosition || "above"
|
||||||
const formField = formApi?.registerField(
|
const formField = formApi?.registerField(
|
||||||
field,
|
field,
|
||||||
type,
|
type,
|
||||||
|
@ -38,17 +38,23 @@
|
||||||
fieldApi = value?.fieldApi
|
fieldApi = value?.fieldApi
|
||||||
fieldSchema = value?.fieldSchema
|
fieldSchema = value?.fieldSchema
|
||||||
})
|
})
|
||||||
onDestroy(() => unsubscribe && unsubscribe())
|
onDestroy(() => unsubscribe?.())
|
||||||
|
|
||||||
// Keep validation rules up to date
|
// Keep field state up to date with props which might change due to
|
||||||
|
// conditional UI
|
||||||
$: updateValidation(validation)
|
$: updateValidation(validation)
|
||||||
|
$: updateDisabled(disabled)
|
||||||
|
|
||||||
|
// Determine label class from position
|
||||||
|
$: labelClass = labelPos === "above" ? "" : `spectrum-FieldLabel--${labelPos}`
|
||||||
|
|
||||||
const updateValidation = validation => {
|
const updateValidation = validation => {
|
||||||
fieldApi?.updateValidation(validation)
|
fieldApi?.updateValidation(validation)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract label position from field group context
|
const updateDisabled = disabled => {
|
||||||
$: labelPositionClass =
|
fieldApi?.setDisabled(disabled)
|
||||||
labelPosition === "above" ? "" : `spectrum-FieldLabel--${labelPosition}`
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FieldGroupFallback>
|
<FieldGroupFallback>
|
||||||
|
@ -56,7 +62,7 @@
|
||||||
<label
|
<label
|
||||||
class:hidden={!label}
|
class:hidden={!label}
|
||||||
for={fieldState?.fieldId}
|
for={fieldState?.fieldId}
|
||||||
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelPositionClass}`}
|
class={`spectrum-FieldLabel spectrum-FieldLabel--sizeM spectrum-Form-itemLabel ${labelClass}`}
|
||||||
>
|
>
|
||||||
{label || ""}
|
{label || ""}
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -248,10 +248,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the disabled state of a certain field
|
||||||
|
const setDisabled = fieldDisabled => {
|
||||||
|
const fieldInfo = getField(field)
|
||||||
|
|
||||||
|
// Auto columns are always disabled
|
||||||
|
const isAutoColumn = !!schema?.[field]?.autocolumn
|
||||||
|
|
||||||
|
// Update disabled state
|
||||||
|
fieldInfo.update(state => {
|
||||||
|
state.fieldState.disabled = disabled || fieldDisabled || isAutoColumn
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setValue,
|
setValue,
|
||||||
clearValue,
|
clearValue,
|
||||||
updateValidation,
|
updateValidation,
|
||||||
|
setDisabled,
|
||||||
validate: () => {
|
validate: () => {
|
||||||
// Validate the field by force setting the same value again
|
// Validate the field by force setting the same value again
|
||||||
const { fieldState } = get(getField(field))
|
const { fieldState } = get(getField(field))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import Provider from "./Provider.svelte"
|
import Provider from "./Provider.svelte"
|
||||||
import { onMount } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
|
|
||||||
let width = window.innerWidth
|
let width = window.innerWidth
|
||||||
let height = window.innerHeight
|
let height = window.innerHeight
|
||||||
|
@ -21,12 +21,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const doc = document.getElementById("app-root")
|
resizeObserver.observe(document.getElementById("app-root"))
|
||||||
resizeObserver.observe(doc)
|
})
|
||||||
|
|
||||||
return () => {
|
onDestroy(() => {
|
||||||
resizeObserver.unobserve(doc)
|
resizeObserver.unobserve(document.getElementById("app-root"))
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext, setContext, onMount } from "svelte"
|
import { getContext, setContext, onDestroy } from "svelte"
|
||||||
import { dataSourceStore, createContextStore } from "stores"
|
import { dataSourceStore, createContextStore } from "stores"
|
||||||
import { ActionTypes } from "constants"
|
import { ActionTypes } from "constants"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
@ -56,9 +56,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onDestroy(() => {
|
||||||
// Unregister all datasource instances when unmounting this provider
|
// Unregister all datasource instances when unmounting this provider
|
||||||
return () => dataSourceStore.actions.unregisterInstance(instanceId)
|
dataSourceStore.actions.unregisterInstance(instanceId)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import IndicatorSet from "./IndicatorSet.svelte"
|
import IndicatorSet from "./IndicatorSet.svelte"
|
||||||
import DNDPositionIndicator from "./DNDPositionIndicator.svelte"
|
import DNDPositionIndicator from "./DNDPositionIndicator.svelte"
|
||||||
|
@ -209,18 +209,18 @@
|
||||||
document.addEventListener("dragenter", onDragEnter, false)
|
document.addEventListener("dragenter", onDragEnter, false)
|
||||||
document.addEventListener("dragleave", onDragLeave, false)
|
document.addEventListener("dragleave", onDragLeave, false)
|
||||||
document.addEventListener("drop", onDrop, false)
|
document.addEventListener("drop", onDrop, false)
|
||||||
|
})
|
||||||
|
|
||||||
return () => {
|
onDestroy(() => {
|
||||||
// Events fired on the draggable target
|
// Events fired on the draggable target
|
||||||
document.removeEventListener("dragstart", onDragStart, false)
|
document.removeEventListener("dragstart", onDragStart, false)
|
||||||
document.removeEventListener("dragend", onDragEnd, false)
|
document.removeEventListener("dragend", onDragEnd, false)
|
||||||
|
|
||||||
// Events fired on the drop targets
|
// Events fired on the drop targets
|
||||||
document.removeEventListener("dragover", onDragOver, false)
|
document.removeEventListener("dragover", onDragOver, false)
|
||||||
document.removeEventListener("dragenter", onDragEnter, false)
|
document.removeEventListener("dragenter", onDragEnter, false)
|
||||||
document.removeEventListener("dragleave", onDragLeave, false)
|
document.removeEventListener("dragleave", onDragLeave, false)
|
||||||
document.removeEventListener("drop", onDrop, false)
|
document.removeEventListener("drop", onDrop, false)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
|
import { fetchTableDefinition } from "../api"
|
||||||
|
|
||||||
export const createDataSourceStore = () => {
|
export const createDataSourceStore = () => {
|
||||||
const store = writable([])
|
const store = writable([])
|
||||||
|
@ -9,43 +10,32 @@ export const createDataSourceStore = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a list of all relevant dataSource IDs which would require that
|
// Extract the relevant datasource ID for this datasource
|
||||||
// this dataSource is refreshed
|
let dataSourceId = null
|
||||||
let dataSourceIds = []
|
|
||||||
|
|
||||||
// Extract table ID
|
// Extract table ID
|
||||||
if (dataSource.type === "table" || dataSource.type === "view") {
|
if (dataSource.type === "table" || dataSource.type === "view") {
|
||||||
if (dataSource.tableId) {
|
dataSourceId = dataSource.tableId
|
||||||
dataSourceIds.push(dataSource.tableId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract both table IDs from both sides of the relationship
|
// Only one side of the relationship is required as a trigger, as it will
|
||||||
|
// automatically invalidate related table IDs
|
||||||
else if (dataSource.type === "link") {
|
else if (dataSource.type === "link") {
|
||||||
if (dataSource.rowTableId) {
|
dataSourceId = dataSource.tableId || dataSource.rowTableId
|
||||||
dataSourceIds.push(dataSource.rowTableId)
|
|
||||||
}
|
|
||||||
if (dataSource.tableId) {
|
|
||||||
dataSourceIds.push(dataSource.tableId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the dataSource ID (not the query ID) for queries
|
// Extract the dataSource ID (not the query ID) for queries
|
||||||
else if (dataSource.type === "query") {
|
else if (dataSource.type === "query") {
|
||||||
if (dataSource.dataSourceId) {
|
dataSourceId = dataSource.dataSourceId
|
||||||
dataSourceIds.push(dataSource.dataSourceId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store configs for each relevant dataSource ID
|
// Store configs for each relevant dataSource ID
|
||||||
if (dataSourceIds.length) {
|
if (dataSourceId) {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
dataSourceIds.forEach(id => {
|
state.push({
|
||||||
state.push({
|
dataSourceId,
|
||||||
dataSourceId: id,
|
instanceId,
|
||||||
instanceId,
|
refresh,
|
||||||
refresh,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
@ -62,13 +52,10 @@ export const createDataSourceStore = () => {
|
||||||
|
|
||||||
// Invalidates a specific dataSource ID by refreshing all instances
|
// Invalidates a specific dataSource ID by refreshing all instances
|
||||||
// which depend on data from that dataSource
|
// which depend on data from that dataSource
|
||||||
const invalidateDataSource = dataSourceId => {
|
const invalidateDataSource = async dataSourceId => {
|
||||||
const relatedInstances = get(store).filter(instance => {
|
if (!dataSourceId) {
|
||||||
return instance.dataSourceId === dataSourceId
|
return
|
||||||
})
|
}
|
||||||
relatedInstances?.forEach(instance => {
|
|
||||||
instance.refresh()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Emit this as a window event, so parent screens which are iframing us in
|
// Emit this as a window event, so parent screens which are iframing us in
|
||||||
// can also invalidate the same datasource
|
// can also invalidate the same datasource
|
||||||
|
@ -77,6 +64,36 @@ export const createDataSourceStore = () => {
|
||||||
detail: { dataSourceId },
|
detail: { dataSourceId },
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let invalidations = [dataSourceId]
|
||||||
|
|
||||||
|
// Fetch related table IDs from table schema
|
||||||
|
const definition = await fetchTableDefinition(dataSourceId)
|
||||||
|
const schema = definition?.schema
|
||||||
|
if (schema) {
|
||||||
|
Object.values(schema).forEach(fieldSchema => {
|
||||||
|
if (
|
||||||
|
fieldSchema.type === "link" &&
|
||||||
|
fieldSchema.tableId &&
|
||||||
|
!fieldSchema.autocolumn
|
||||||
|
) {
|
||||||
|
invalidations.push(fieldSchema.tableId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any dupes
|
||||||
|
invalidations = [...new Set(invalidations)]
|
||||||
|
|
||||||
|
// Invalidate all sources
|
||||||
|
invalidations.forEach(id => {
|
||||||
|
const relatedInstances = get(store).filter(instance => {
|
||||||
|
return instance.dataSourceId === id
|
||||||
|
})
|
||||||
|
relatedInstances?.forEach(instance => {
|
||||||
|
instance.refresh()
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in New Issue