Add data provider component and refactor component setting types
This commit is contained in:
parent
2685d46266
commit
6e29423d4d
|
@ -35,7 +35,7 @@ export const getDataProviderComponents = (asset, componentId) => {
|
||||||
// Filter by only data provider components
|
// Filter by only data provider components
|
||||||
return path.filter(component => {
|
return path.filter(component => {
|
||||||
const def = store.actions.components.getDefinition(component._component)
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
return def?.dataProvider
|
return def?.dataContext != null
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,15 +101,16 @@ const getContextBindings = (asset, componentId) => {
|
||||||
|
|
||||||
// Create bindings for each data provider
|
// Create bindings for each data provider
|
||||||
dataProviders.forEach(component => {
|
dataProviders.forEach(component => {
|
||||||
const isForm = component._component.endsWith("/form")
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
const datasource = getDatasourceForProvider(component)
|
const contextDefinition = def.dataContext
|
||||||
let tableName, schema
|
let schema
|
||||||
|
|
||||||
// Forms are an edge case which do not need table schemas
|
// Forms are an edge case which do not need table schemas
|
||||||
if (isForm) {
|
if (contextDefinition.type === "form") {
|
||||||
schema = buildFormSchema(component)
|
schema = buildFormSchema(component)
|
||||||
tableName = "Fields"
|
tableName = "Fields"
|
||||||
} else {
|
} else {
|
||||||
|
const datasource = getDatasourceForProvider(component)
|
||||||
if (!datasource) {
|
if (!datasource) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[
|
[
|
||||||
"container",
|
"container",
|
||||||
|
"dataprovider",
|
||||||
"datagrid",
|
"datagrid",
|
||||||
"list",
|
"list",
|
||||||
"button",
|
"button",
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<script>
|
||||||
|
import { Select } from "@budibase/bbui"
|
||||||
|
import { currentAsset, store } from "builderStore"
|
||||||
|
import { findComponentPath } from "builderStore/storeUtils"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
|
||||||
|
$: path = findComponentPath($currentAsset.props, $store.selectedComponentId)
|
||||||
|
$: console.log(path)
|
||||||
|
$: providers = path.filter(
|
||||||
|
component =>
|
||||||
|
component._component === "@budibase/standard-components/dataprovider"
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select thin secondary {value} on:change>
|
||||||
|
<option value="">Choose option</option>
|
||||||
|
{#if providers}
|
||||||
|
{#each providers as component}
|
||||||
|
<option value={component._id}>{component._instanceName}</option>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</Select>
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import DatasourceSelect from "./DatasourceSelect.svelte"
|
import DataSourceSelect from "./DataSourceSelect.svelte"
|
||||||
|
|
||||||
const otherSources = [{ name: "Custom", label: "Custom" }]
|
const otherSources = [{ name: "Custom", label: "Custom" }]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DatasourceSelect on:change {...$$props} showAllQueries={true} {otherSources} />
|
<DataSourceSelect on:change {...$$props} showAllQueries={true} {otherSources} />
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
import OptionSelect from "./PropertyControls/OptionSelect.svelte"
|
import OptionSelect from "./PropertyControls/OptionSelect.svelte"
|
||||||
import Checkbox from "./PropertyControls/Checkbox.svelte"
|
import Checkbox from "./PropertyControls/Checkbox.svelte"
|
||||||
import TableSelect from "./PropertyControls/TableSelect.svelte"
|
import TableSelect from "./PropertyControls/TableSelect.svelte"
|
||||||
import DatasourceSelect from "./PropertyControls/DatasourceSelect.svelte"
|
import DataSourceSelect from "./PropertyControls/DataSourceSelect.svelte"
|
||||||
|
import DataProviderSelect from "./PropertyControls/DataProviderSelect.svelte"
|
||||||
import FieldSelect from "./PropertyControls/FieldSelect.svelte"
|
import FieldSelect from "./PropertyControls/FieldSelect.svelte"
|
||||||
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
|
import MultiFieldSelect from "./PropertyControls/MultiFieldSelect.svelte"
|
||||||
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
|
import SchemaSelect from "./PropertyControls/SchemaSelect.svelte"
|
||||||
|
@ -61,7 +62,8 @@
|
||||||
const controlMap = {
|
const controlMap = {
|
||||||
text: Input,
|
text: Input,
|
||||||
select: OptionSelect,
|
select: OptionSelect,
|
||||||
datasource: DatasourceSelect,
|
dataSource: DataSourceSelect,
|
||||||
|
dataProvider: DataProviderSelect,
|
||||||
detailScreen: DetailScreenSelect,
|
detailScreen: DetailScreenSelect,
|
||||||
boolean: Checkbox,
|
boolean: Checkbox,
|
||||||
number: Input,
|
number: Input,
|
||||||
|
|
|
@ -7,31 +7,31 @@ import { executeQuery } from "./queries"
|
||||||
/**
|
/**
|
||||||
* Fetches all rows for a particular Budibase data source.
|
* Fetches all rows for a particular Budibase data source.
|
||||||
*/
|
*/
|
||||||
export const fetchDatasource = async datasource => {
|
export const fetchDatasource = async dataSource => {
|
||||||
if (!datasource || !datasource.type) {
|
if (!dataSource || !dataSource.type) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch all rows in data source
|
// Fetch all rows in data source
|
||||||
const { type, tableId, fieldName } = datasource
|
const { type, tableId, fieldName } = dataSource
|
||||||
let rows = []
|
let rows = []
|
||||||
if (type === "table") {
|
if (type === "table") {
|
||||||
rows = await fetchTableData(tableId)
|
rows = await fetchTableData(tableId)
|
||||||
} else if (type === "view") {
|
} else if (type === "view") {
|
||||||
rows = await fetchViewData(datasource)
|
rows = await fetchViewData(dataSource)
|
||||||
} else if (type === "query") {
|
} else if (type === "query") {
|
||||||
// Set the default query params
|
// Set the default query params
|
||||||
let parameters = cloneDeep(datasource.queryParams || {})
|
let parameters = cloneDeep(dataSource.queryParams || {})
|
||||||
for (let param of datasource.parameters) {
|
for (let param of dataSource.parameters) {
|
||||||
if (!parameters[param.name]) {
|
if (!parameters[param.name]) {
|
||||||
parameters[param.name] = param.default
|
parameters[param.name] = param.default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = await executeQuery({ queryId: datasource._id, parameters })
|
rows = await executeQuery({ queryId: dataSource._id, parameters })
|
||||||
} else if (type === "link") {
|
} else if (type === "link") {
|
||||||
rows = await fetchRelationshipData({
|
rows = await fetchRelationshipData({
|
||||||
rowId: datasource.rowId,
|
rowId: dataSource.rowId,
|
||||||
tableId: datasource.rowTableId,
|
tableId: dataSource.rowTableId,
|
||||||
fieldName,
|
fieldName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { notificationStore, datasourceStore } from "../store"
|
import { notificationStore, dataSourceStore } from "../store"
|
||||||
import API from "./api"
|
import API from "./api"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,7 @@ export const executeQuery = async ({ queryId, parameters }) => {
|
||||||
notificationStore.danger("An error has occurred")
|
notificationStore.danger("An error has occurred")
|
||||||
} else if (!query.readable) {
|
} else if (!query.readable) {
|
||||||
notificationStore.success("Query executed successfully")
|
notificationStore.success("Query executed successfully")
|
||||||
datasourceStore.actions.invalidateDatasource(query.datasourceId)
|
dataSourceStore.actions.invalidateDataSource(query.datasourceId)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { notificationStore, datasourceStore } from "../store"
|
import { notificationStore, dataSourceStore } from "../store"
|
||||||
import API from "./api"
|
import API from "./api"
|
||||||
import { fetchTableDefinition } from "./tables"
|
import { fetchTableDefinition } from "./tables"
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ export const saveRow = async row => {
|
||||||
: notificationStore.success("Row saved")
|
: notificationStore.success("Row saved")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
datasourceStore.actions.invalidateDatasource(row.tableId)
|
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ export const updateRow = async row => {
|
||||||
: notificationStore.success("Row updated")
|
: notificationStore.success("Row updated")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
datasourceStore.actions.invalidateDatasource(row.tableId)
|
dataSourceStore.actions.invalidateDataSource(row.tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export const deleteRow = async ({ tableId, rowId, revId }) => {
|
||||||
: notificationStore.success("Row deleted")
|
: notificationStore.success("Row deleted")
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
datasourceStore.actions.invalidateDatasource(tableId)
|
dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ export const deleteRows = async ({ tableId, rows }) => {
|
||||||
: notificationStore.success(`${rows.length} row(s) deleted`)
|
: notificationStore.success(`${rows.length} row(s) deleted`)
|
||||||
|
|
||||||
// Refresh related datasources
|
// Refresh related datasources
|
||||||
datasourceStore.actions.invalidateDatasource(tableId)
|
dataSourceStore.actions.invalidateDataSource(tableId)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
{
|
{
|
||||||
type: ActionTypes.RefreshDatasource,
|
type: ActionTypes.RefreshDatasource,
|
||||||
callback: () => authStore.actions.fetchUser(),
|
callback: () => authStore.actions.fetchUser(),
|
||||||
metadata: { datasource: { type: "table", tableId: TableNames.USERS } },
|
metadata: { dataSource: { type: "table", tableId: TableNames.USERS } },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext, setContext, onMount } from "svelte"
|
import { getContext, setContext, onMount } from "svelte"
|
||||||
import { datasourceStore, createContextStore } from "../store"
|
import { dataSourceStore, createContextStore } from "../store"
|
||||||
import { ActionTypes } from "../constants"
|
import { ActionTypes } from "../constants"
|
||||||
import { generate } from "shortid"
|
import { generate } from "shortid"
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@
|
||||||
// Register any "refresh datasource" actions with a singleton store
|
// Register any "refresh datasource" actions with a singleton store
|
||||||
// so we can easily refresh data at all levels for any datasource
|
// so we can easily refresh data at all levels for any datasource
|
||||||
if (type === ActionTypes.RefreshDatasource) {
|
if (type === ActionTypes.RefreshDatasource) {
|
||||||
const { datasource } = metadata || {}
|
const { dataSource } = metadata || {}
|
||||||
datasourceStore.actions.registerDatasource(
|
dataSourceStore.actions.registerDataSource(
|
||||||
datasource,
|
dataSource,
|
||||||
instanceId,
|
instanceId,
|
||||||
callback
|
callback
|
||||||
)
|
)
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
instanceId = generate()
|
instanceId = generate()
|
||||||
|
|
||||||
// Unregister all datasource instances when unmounting this provider
|
// Unregister all datasource instances when unmounting this provider
|
||||||
return () => datasourceStore.actions.unregisterInstance(instanceId)
|
return () => dataSourceStore.actions.unregisterInstance(instanceId)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import { writable, get } from "svelte/store"
|
||||||
|
import { notificationStore } from "./notification"
|
||||||
|
|
||||||
|
export const createDataSourceStore = () => {
|
||||||
|
const store = writable([])
|
||||||
|
|
||||||
|
// Registers a new dataSource instance
|
||||||
|
const registerDataSource = (dataSource, instanceId, refresh) => {
|
||||||
|
if (!dataSource || !instanceId || !refresh) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a list of all relevant dataSource IDs which would require that
|
||||||
|
// this dataSource is refreshed
|
||||||
|
let dataSourceIds = []
|
||||||
|
|
||||||
|
// Extract table ID
|
||||||
|
if (dataSource.type === "table" || dataSource.type === "view") {
|
||||||
|
if (dataSource.tableId) {
|
||||||
|
dataSourceIds.push(dataSource.tableId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract both table IDs from both sides of the relationship
|
||||||
|
else if (dataSource.type === "link") {
|
||||||
|
if (dataSource.rowTableId) {
|
||||||
|
dataSourceIds.push(dataSource.rowTableId)
|
||||||
|
}
|
||||||
|
if (dataSource.tableId) {
|
||||||
|
dataSourceIds.push(dataSource.tableId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the dataSource ID (not the query ID) for queries
|
||||||
|
else if (dataSource.type === "query") {
|
||||||
|
if (dataSource.dataSourceId) {
|
||||||
|
dataSourceIds.push(dataSource.dataSourceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store configs for each relevant dataSource ID
|
||||||
|
if (dataSourceIds.length) {
|
||||||
|
store.update(state => {
|
||||||
|
dataSourceIds.forEach(id => {
|
||||||
|
state.push({
|
||||||
|
dataSourceId: id,
|
||||||
|
instanceId,
|
||||||
|
refresh,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all registered dataSource instances belonging to a particular
|
||||||
|
// instance ID
|
||||||
|
const unregisterInstance = instanceId => {
|
||||||
|
store.update(state => {
|
||||||
|
return state.filter(instance => instance.instanceId !== instanceId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidates a specific dataSource ID by refreshing all instances
|
||||||
|
// which depend on data from that dataSource
|
||||||
|
const invalidateDataSource = dataSourceId => {
|
||||||
|
const relatedInstances = get(store).filter(instance => {
|
||||||
|
return instance.dataSourceId === dataSourceId
|
||||||
|
})
|
||||||
|
if (relatedInstances?.length) {
|
||||||
|
notificationStore.blockNotifications(1000)
|
||||||
|
}
|
||||||
|
relatedInstances?.forEach(instance => {
|
||||||
|
instance.refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe: store.subscribe,
|
||||||
|
actions: { registerDataSource, unregisterInstance, invalidateDataSource },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dataSourceStore = createDataSourceStore()
|
|
@ -1,84 +0,0 @@
|
||||||
import { writable, get } from "svelte/store"
|
|
||||||
import { notificationStore } from "./notification"
|
|
||||||
|
|
||||||
export const createDatasourceStore = () => {
|
|
||||||
const store = writable([])
|
|
||||||
|
|
||||||
// Registers a new datasource instance
|
|
||||||
const registerDatasource = (datasource, instanceId, refresh) => {
|
|
||||||
if (!datasource || !instanceId || !refresh) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a list of all relevant datasource IDs which would require that
|
|
||||||
// this datasource is refreshed
|
|
||||||
let datasourceIds = []
|
|
||||||
|
|
||||||
// Extract table ID
|
|
||||||
if (datasource.type === "table" || datasource.type === "view") {
|
|
||||||
if (datasource.tableId) {
|
|
||||||
datasourceIds.push(datasource.tableId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract both table IDs from both sides of the relationship
|
|
||||||
else if (datasource.type === "link") {
|
|
||||||
if (datasource.rowTableId) {
|
|
||||||
datasourceIds.push(datasource.rowTableId)
|
|
||||||
}
|
|
||||||
if (datasource.tableId) {
|
|
||||||
datasourceIds.push(datasource.tableId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the datasource ID (not the query ID) for queries
|
|
||||||
else if (datasource.type === "query") {
|
|
||||||
if (datasource.datasourceId) {
|
|
||||||
datasourceIds.push(datasource.datasourceId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store configs for each relevant datasource ID
|
|
||||||
if (datasourceIds.length) {
|
|
||||||
store.update(state => {
|
|
||||||
datasourceIds.forEach(id => {
|
|
||||||
state.push({
|
|
||||||
datasourceId: id,
|
|
||||||
instanceId,
|
|
||||||
refresh,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removes all registered datasource instances belonging to a particular
|
|
||||||
// instance ID
|
|
||||||
const unregisterInstance = instanceId => {
|
|
||||||
store.update(state => {
|
|
||||||
return state.filter(instance => instance.instanceId !== instanceId)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalidates a specific datasource ID by refreshing all instances
|
|
||||||
// which depend on data from that datasource
|
|
||||||
const invalidateDatasource = datasourceId => {
|
|
||||||
const relatedInstances = get(store).filter(instance => {
|
|
||||||
return instance.datasourceId === datasourceId
|
|
||||||
})
|
|
||||||
if (relatedInstances?.length) {
|
|
||||||
notificationStore.blockNotifications(1000)
|
|
||||||
}
|
|
||||||
relatedInstances?.forEach(instance => {
|
|
||||||
instance.refresh()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe: store.subscribe,
|
|
||||||
actions: { registerDatasource, unregisterInstance, invalidateDatasource },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const datasourceStore = createDatasourceStore()
|
|
|
@ -3,7 +3,7 @@ export { notificationStore } from "./notification"
|
||||||
export { routeStore } from "./routes"
|
export { routeStore } from "./routes"
|
||||||
export { screenStore } from "./screens"
|
export { screenStore } from "./screens"
|
||||||
export { builderStore } from "./builder"
|
export { builderStore } from "./builder"
|
||||||
export { datasourceStore } from "./datasource"
|
export { dataSourceStore } from "./dataSource"
|
||||||
|
|
||||||
// Context stores are layered and duplicated, so it is not a singleton
|
// Context stores are layered and duplicated, so it is not a singleton
|
||||||
export { createContextStore } from "./context"
|
export { createContextStore } from "./context"
|
||||||
|
|
|
@ -84,13 +84,11 @@
|
||||||
"icon": "ri-list-check-2",
|
"icon": "ri-list-check-2",
|
||||||
"styleable": true,
|
"styleable": true,
|
||||||
"hasChildren": true,
|
"hasChildren": true,
|
||||||
"dataProvider": true,
|
|
||||||
"actions": ["RefreshDatasource"],
|
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"type": "datasource",
|
"type": "dataProvider",
|
||||||
"label": "Data",
|
"label": "Data",
|
||||||
"key": "datasource"
|
"key": "dataProviderId"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -103,7 +101,11 @@
|
||||||
"label": "Filtering",
|
"label": "Filtering",
|
||||||
"key": "filter"
|
"key": "filter"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"dataContext": {
|
||||||
|
"type": "schema",
|
||||||
|
"dataProviderSetting": "dataProviderId"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"name": "Search",
|
"name": "Search",
|
||||||
|
@ -1472,5 +1474,44 @@
|
||||||
"defaultValue": false
|
"defaultValue": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"dataprovider": {
|
||||||
|
"name": "Data Provider",
|
||||||
|
"icon": "ri-database-2-line",
|
||||||
|
"styleable": false,
|
||||||
|
"hasChildren": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "dataSource",
|
||||||
|
"label": "Data",
|
||||||
|
"key": "dataSource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "filter",
|
||||||
|
"label": "Filtering",
|
||||||
|
"key": "filter"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dataContext": {
|
||||||
|
"type": "static",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"label": "Rows",
|
||||||
|
"key": "rows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Rows Length",
|
||||||
|
"key": "rowsLength"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Loading",
|
||||||
|
"key": "loading"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Loaded",
|
||||||
|
"key": "loaded"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
|
export let dataSource
|
||||||
|
export let filter
|
||||||
|
export let sortColumn
|
||||||
|
export let sortOrder
|
||||||
|
export let limit
|
||||||
|
|
||||||
|
const { API, styleable, Provider, ActionTypes } = getContext("sdk")
|
||||||
|
const component = getContext("component")
|
||||||
|
|
||||||
|
// Loading flag every time data is being fetched
|
||||||
|
let loading = false
|
||||||
|
|
||||||
|
// Loading flag for the initial load
|
||||||
|
let loaded = false
|
||||||
|
|
||||||
|
let allRows = []
|
||||||
|
$: fetchData(dataSource)
|
||||||
|
$: filteredRows = filterRows(allRows, filter)
|
||||||
|
$: sortedRows = sortRows(filteredRows, sortColumn, sortOrder)
|
||||||
|
$: rows = limitRows(sortedRows, limit)
|
||||||
|
$: {
|
||||||
|
console.log(allRows)
|
||||||
|
console.log(filteredRows)
|
||||||
|
console.log(sortedRows)
|
||||||
|
console.log(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
$: actions = [
|
||||||
|
{
|
||||||
|
type: ActionTypes.RefreshDatasource,
|
||||||
|
callback: () => fetchData(dataSource),
|
||||||
|
metadata: { dataSource },
|
||||||
|
},
|
||||||
|
]
|
||||||
|
$: dataContext = {
|
||||||
|
rows,
|
||||||
|
rowsLength: rows.length,
|
||||||
|
loading,
|
||||||
|
loaded,
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchData = async dataSource => {
|
||||||
|
loading = true
|
||||||
|
allRows = await API.fetchDatasource(dataSource)
|
||||||
|
loading = false
|
||||||
|
loaded = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterRows = (rows, filter) => {
|
||||||
|
if (!Object.keys(filter || {}).length) {
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
let filteredData = [...rows]
|
||||||
|
Object.entries(filter).forEach(([field, value]) => {
|
||||||
|
if (value != null && value !== "") {
|
||||||
|
filteredData = filteredData.filter(row => {
|
||||||
|
return row[field] === value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return filteredData
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortRows = (rows, sortColumn, sortOrder) => {
|
||||||
|
if (!sortColumn || !sortOrder) {
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
return rows.slice().sort((a, b) => {
|
||||||
|
const colA = a[sortColumn]
|
||||||
|
const colB = b[sortColumn]
|
||||||
|
if (sortOrder === "descending") {
|
||||||
|
return colA > colB ? -1 : 1
|
||||||
|
} else {
|
||||||
|
return colA > colB ? 1 : -1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const limitRows = (rows, limit) => {
|
||||||
|
const numLimit = parseFloat(limit)
|
||||||
|
if (isNaN(numLimit)) {
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
return rows.slice(0, numLimit)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Provider {actions} data={dataContext}>
|
||||||
|
<slot />
|
||||||
|
</Provider>
|
|
@ -1,68 +1,32 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { isEmpty } from "lodash/fp"
|
|
||||||
|
|
||||||
export let datasource
|
export let dataProviderId
|
||||||
export let noRowsMessage
|
export let noRowsMessage
|
||||||
export let filter
|
|
||||||
|
|
||||||
const { API, styleable, Provider, builderStore, ActionTypes } = getContext(
|
const { API, styleable, builderStore, Provider } = getContext("sdk")
|
||||||
"sdk"
|
|
||||||
)
|
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
let rows = []
|
const context = getContext("context")
|
||||||
let loaded = false
|
|
||||||
|
|
||||||
$: fetchData(datasource)
|
$: data = context[dataProviderId]?.rows ?? []
|
||||||
$: filteredRows = filterRows(rows, filter)
|
$: loaded = context[dataProviderId]?.loaded ?? false
|
||||||
$: actions = [
|
|
||||||
{
|
|
||||||
type: ActionTypes.RefreshDatasource,
|
|
||||||
callback: () => fetchData(datasource),
|
|
||||||
metadata: { datasource },
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const fetchData = async datasource => {
|
|
||||||
if (!isEmpty(datasource)) {
|
|
||||||
rows = await API.fetchDatasource(datasource)
|
|
||||||
}
|
|
||||||
loaded = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterRows = (rows, filter) => {
|
|
||||||
if (!Object.keys(filter || {}).length) {
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
let filteredData = [...rows]
|
|
||||||
Object.entries(filter).forEach(([field, value]) => {
|
|
||||||
if (value != null && value !== "") {
|
|
||||||
filteredData = filteredData.filter(row => {
|
|
||||||
return row[field] === value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return filteredData
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Provider {actions}>
|
<div use:styleable={$component.styles}>
|
||||||
<div use:styleable={$component.styles}>
|
{#if data.length > 0}
|
||||||
{#if filteredRows.length > 0}
|
{#if $component.children === 0 && $builderStore.inBuilder}
|
||||||
{#if $component.children === 0 && $builderStore.inBuilder}
|
<p><i class="ri-image-line" />Add some components to display.</p>
|
||||||
<p><i class="ri-image-line" />Add some components to display.</p>
|
{:else}
|
||||||
{:else}
|
{#each data as row}
|
||||||
{#each filteredRows as row}
|
<Provider data={row}>
|
||||||
<Provider data={row}>
|
<slot />
|
||||||
<slot />
|
</Provider>
|
||||||
</Provider>
|
{/each}
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
{:else if loaded && noRowsMessage}
|
|
||||||
<p><i class="ri-list-check-2" />{noRowsMessage}</p>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
{:else if loaded && noRowsMessage}
|
||||||
</Provider>
|
<p><i class="ri-list-check-2" />{noRowsMessage}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
p {
|
p {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { loadSpectrumIcons } from "./spectrum-icons"
|
||||||
loadSpectrumIcons()
|
loadSpectrumIcons()
|
||||||
|
|
||||||
export { default as container } from "./Container.svelte"
|
export { default as container } from "./Container.svelte"
|
||||||
|
export { default as dataprovider } from "./DataProvider.svelte"
|
||||||
export { default as datagrid } from "./grid/Component.svelte"
|
export { default as datagrid } from "./grid/Component.svelte"
|
||||||
export { default as screenslot } from "./ScreenSlot.svelte"
|
export { default as screenslot } from "./ScreenSlot.svelte"
|
||||||
export { default as button } from "./Button.svelte"
|
export { default as button } from "./Button.svelte"
|
||||||
|
|
Loading…
Reference in New Issue