forked from tsai/budibase
18 changed files with 302 additions and 176 deletions
@ -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} /> |
||||
|
|||||
@ -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() |
|
||||
@ -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> |
||||
Loading…
Reference in new issue