Refactor all backend stores and their usages to use new core API and handle errors
This commit is contained in:
parent
816ced96df
commit
453386696f
|
@ -5,7 +5,6 @@ import {
|
||||||
} from "@budibase/frontend-core"
|
} from "@budibase/frontend-core"
|
||||||
import { store } from "./index"
|
import { store } from "./index"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { notifications } from "@budibase/bbui"
|
|
||||||
|
|
||||||
export const API = createAPIClient({
|
export const API = createAPIClient({
|
||||||
attachHeaders: headers => {
|
attachHeaders: headers => {
|
||||||
|
@ -25,11 +24,6 @@ export const API = createAPIClient({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show a notification for any errors
|
|
||||||
if (message) {
|
|
||||||
notifications.error(`Error fetching ${url}: ${message}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log all errors to console
|
// Log all errors to console
|
||||||
console.error(`HTTP ${status} on ${method}:${url}:\n\t${message}`)
|
console.error(`HTTP ${status} on ${method}:${url}:\n\t${message}`)
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,13 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
function saveView() {
|
function saveView() {
|
||||||
|
try {
|
||||||
views.save(view)
|
views.save(view)
|
||||||
notifications.success(`View ${view.name} saved.`)
|
notifications.success(`View ${view.name} saved`)
|
||||||
analytics.captureEvent(Events.VIEW.ADDED_CALCULATE, { field: view.field })
|
analytics.captureEvent(Events.VIEW.ADDED_CALCULATE, { field: view.field })
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error saving view")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
})
|
})
|
||||||
dispatch("updatecolumns")
|
dispatch("updatecolumns")
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error(err)
|
notifications.error("Error saving column")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteColumn() {
|
function deleteColumn() {
|
||||||
|
try {
|
||||||
field.name = deleteColName
|
field.name = deleteColName
|
||||||
if (field.name === $tables.selected.primaryDisplay) {
|
if (field.name === $tables.selected.primaryDisplay) {
|
||||||
notifications.error("You cannot delete the display column")
|
notifications.error("You cannot delete the display column")
|
||||||
|
@ -140,9 +141,12 @@
|
||||||
confirmDeleteDialog.hide()
|
confirmDeleteDialog.hide()
|
||||||
hide()
|
hide()
|
||||||
deletion = false
|
deletion = false
|
||||||
}
|
|
||||||
dispatch("updatecolumns")
|
dispatch("updatecolumns")
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error deleting column")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleTypeChange(event) {
|
function handleTypeChange(event) {
|
||||||
// remove any extra fields that may not be related to this type
|
// remove any extra fields that may not be related to this type
|
||||||
|
|
|
@ -12,9 +12,10 @@
|
||||||
|
|
||||||
function saveView() {
|
function saveView() {
|
||||||
if (views.includes(name)) {
|
if (views.includes(name)) {
|
||||||
notifications.error(`View exists with name ${name}.`)
|
notifications.error(`View exists with name ${name}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
viewsStore.save({
|
viewsStore.save({
|
||||||
name,
|
name,
|
||||||
tableId: $tables.selected._id,
|
tableId: $tables.selected._id,
|
||||||
|
@ -23,6 +24,9 @@
|
||||||
notifications.success(`View ${name} created`)
|
notifications.success(`View ${name} created`)
|
||||||
analytics.captureEvent(Events.VIEW.CREATED, { name })
|
analytics.captureEvent(Events.VIEW.CREATED, { name })
|
||||||
$goto(`../../view/${name}`)
|
$goto(`../../view/${name}`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error creating view")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -72,11 +72,15 @@
|
||||||
$: schema = viewTable && viewTable.schema ? viewTable.schema : {}
|
$: schema = viewTable && viewTable.schema ? viewTable.schema : {}
|
||||||
|
|
||||||
function saveView() {
|
function saveView() {
|
||||||
|
try {
|
||||||
views.save(view)
|
views.save(view)
|
||||||
notifications.success(`View ${view.name} saved.`)
|
notifications.success(`View ${view.name} saved`)
|
||||||
analytics.captureEvent(Events.VIEW.ADDED_FILTER, {
|
analytics.captureEvent(Events.VIEW.ADDED_FILTER, {
|
||||||
filters: JSON.stringify(view.filters),
|
filters: JSON.stringify(view.filters),
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifcations.error("Error saving view")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFilter(idx) {
|
function removeFilter(idx) {
|
||||||
|
|
|
@ -19,8 +19,12 @@
|
||||||
.map(([key]) => key)
|
.map(([key]) => key)
|
||||||
|
|
||||||
function saveView() {
|
function saveView() {
|
||||||
|
try {
|
||||||
views.save(view)
|
views.save(view)
|
||||||
notifications.success(`View ${view.name} saved.`)
|
notifications.success(`View ${view.name} saved`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error saving view")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
export let permissions
|
export let permissions
|
||||||
|
|
||||||
async function changePermission(level, role) {
|
async function changePermission(level, role) {
|
||||||
|
try {
|
||||||
await permissionsStore.save({
|
await permissionsStore.save({
|
||||||
level,
|
level,
|
||||||
role,
|
role,
|
||||||
|
@ -22,7 +23,10 @@
|
||||||
|
|
||||||
// Show updated permissions in UI: REMOVE
|
// Show updated permissions in UI: REMOVE
|
||||||
permissions = await permissionsStore.forResource(resourceId)
|
permissions = await permissionsStore.forResource(resourceId)
|
||||||
notifications.success("Updated permissions.")
|
notifications.success("Updated permissions")
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error updating permissions")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
|
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
|
||||||
import { customQueryIconText, customQueryIconColor } from "helpers/data/utils"
|
import { customQueryIconText, customQueryIconColor } from "helpers/data/utils"
|
||||||
import ICONS from "./icons"
|
import ICONS from "./icons"
|
||||||
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
let openDataSources = []
|
let openDataSources = []
|
||||||
$: enrichedDataSources = Array.isArray($datasources.list)
|
$: enrichedDataSources = Array.isArray($datasources.list)
|
||||||
|
@ -64,8 +65,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
try {
|
||||||
datasources.fetch()
|
datasources.fetch()
|
||||||
queries.fetch()
|
queries.fetch()
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching datasources and queries")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const containsActiveEntity = datasource => {
|
const containsActiveEntity = datasource => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { ModalContent, Body, Input } from "@budibase/bbui"
|
import { ModalContent, Body, Input, notifications } from "@budibase/bbui"
|
||||||
import { tables, datasources } from "stores/backend"
|
import { tables, datasources } from "stores/backend"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
|
@ -29,10 +29,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveTable() {
|
async function saveTable() {
|
||||||
|
try {
|
||||||
submitted = true
|
submitted = true
|
||||||
const table = await tables.save(buildDefaultTable(name, datasource._id))
|
const table = await tables.save(buildDefaultTable(name, datasource._id))
|
||||||
await datasources.fetch()
|
await datasources.fetch()
|
||||||
$goto(`../../table/${table._id}`)
|
$goto(`../../table/${table._id}`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error saving table")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,8 @@
|
||||||
await datasources.updateSchema(datasource)
|
await datasources.updateSchema(datasource)
|
||||||
notifications.success(`Datasource ${name} tables updated successfully.`)
|
notifications.success(`Datasource ${name} tables updated successfully.`)
|
||||||
await tables.fetch()
|
await tables.fetch()
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
notifications.error(`Error updating datasource schema: ${err}`)
|
notifications.error("Error updating datasource schema")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,13 @@
|
||||||
externalDatasourceModal.hide()
|
externalDatasourceModal.hide()
|
||||||
internalTableModal.show()
|
internalTableModal.show()
|
||||||
} else if (integration.type === IntegrationTypes.REST) {
|
} else if (integration.type === IntegrationTypes.REST) {
|
||||||
// skip modal for rest, create straight away
|
try {
|
||||||
|
// Skip modal for rest, create straight away
|
||||||
const resp = await createRestDatasource(integration)
|
const resp = await createRestDatasource(integration)
|
||||||
$goto(`./datasource/${resp._id}`)
|
$goto(`./datasource/${resp._id}`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error creating datasource")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
externalDatasourceModal.show()
|
externalDatasourceModal.show()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
$goto(`./datasource/${resp._id}`)
|
$goto(`./datasource/${resp._id}`)
|
||||||
notifications.success(`Datasource updated successfully.`)
|
notifications.success(`Datasource updated successfully.`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error(`Error saving datasource: ${err}`)
|
notifications.error("Error saving datasource")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
notifications.error(`Error importing: ${err}`)
|
notifications.error("Error importing queries")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
let updateDatasourceDialog
|
let updateDatasourceDialog
|
||||||
|
|
||||||
async function deleteDatasource() {
|
async function deleteDatasource() {
|
||||||
|
try {
|
||||||
let wasSelectedSource = $datasources.selected
|
let wasSelectedSource = $datasources.selected
|
||||||
if (!wasSelectedSource && $queries.selected) {
|
if (!wasSelectedSource && $queries.selected) {
|
||||||
const queryId = $queries.selected
|
const queryId = $queries.selected
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
const wasSelectedTable = $tables.selected
|
const wasSelectedTable = $tables.selected
|
||||||
await datasources.delete(datasource)
|
await datasources.delete(datasource)
|
||||||
notifications.success("Datasource deleted")
|
notifications.success("Datasource deleted")
|
||||||
// navigate to first index page if the source you are deleting is selected
|
// Navigate to first index page if the source you are deleting is selected
|
||||||
const entities = Object.values(datasource?.entities || {})
|
const entities = Object.values(datasource?.entities || {})
|
||||||
if (
|
if (
|
||||||
wasSelectedSource === datasource._id ||
|
wasSelectedSource === datasource._id ||
|
||||||
|
@ -31,6 +32,9 @@
|
||||||
) {
|
) {
|
||||||
$goto("./datasource")
|
$goto("./datasource")
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error deleting datasource")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
let confirmDeleteDialog
|
let confirmDeleteDialog
|
||||||
|
|
||||||
async function deleteQuery() {
|
async function deleteQuery() {
|
||||||
|
try {
|
||||||
const wasSelectedQuery = $queries.selected
|
const wasSelectedQuery = $queries.selected
|
||||||
// need to calculate this before the query is deleted
|
// need to calculate this before the query is deleted
|
||||||
const navigateToDatasource = wasSelectedQuery === query._id
|
const navigateToDatasource = wasSelectedQuery === query._id
|
||||||
|
@ -22,14 +23,17 @@
|
||||||
$goto(`./datasource/${query.datasourceId}`)
|
$goto(`./datasource/${query.datasourceId}`)
|
||||||
}
|
}
|
||||||
notifications.success("Query deleted")
|
notifications.success("Query deleted")
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error deleting query")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function duplicateQuery() {
|
async function duplicateQuery() {
|
||||||
try {
|
try {
|
||||||
const newQuery = await queries.duplicate(query)
|
const newQuery = await queries.duplicate(query)
|
||||||
onClickQuery(newQuery)
|
onClickQuery(newQuery)
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
notifications.error(e.message)
|
notifications.error("Error duplicating query")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -49,8 +49,8 @@
|
||||||
if (wasSelectedTable && wasSelectedTable._id === table._id) {
|
if (wasSelectedTable && wasSelectedTable._id === table._id) {
|
||||||
$goto("./table")
|
$goto("./table")
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
notifications.error(err)
|
notifications.error("Error deleting table")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteView() {
|
async function deleteView() {
|
||||||
|
try {
|
||||||
const name = view.name
|
const name = view.name
|
||||||
const id = view.tableId
|
const id = view.tableId
|
||||||
await views.delete(name)
|
await views.delete(name)
|
||||||
notifications.success("View deleted")
|
notifications.success("View deleted")
|
||||||
$goto(`./table/${id}`)
|
$goto(`./table/${id}`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error deleting view")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Label, Select } from "@budibase/bbui"
|
import { Label, notifications, Select } from "@budibase/bbui"
|
||||||
import { permissions, roles } from "stores/backend"
|
import { permissions, roles } from "stores/backend"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { Roles } from "constants/backend"
|
import { Roles } from "constants/backend"
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
let roleId, loaded
|
let roleId, loaded
|
||||||
|
|
||||||
async function updateRole(role, id) {
|
async function updateRole(role, id) {
|
||||||
|
try {
|
||||||
roleId = role
|
roleId = role
|
||||||
const queryId = query?._id || id
|
const queryId = query?._id || id
|
||||||
if (roleId && queryId) {
|
if (roleId && queryId) {
|
||||||
|
@ -24,6 +25,9 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error updating role")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
|
|
@ -71,9 +71,9 @@
|
||||||
}
|
}
|
||||||
data = response.rows
|
data = response.rows
|
||||||
fields = response.schema
|
fields = response.schema
|
||||||
notifications.success("Query executed successfully.")
|
notifications.success("Query executed successfully")
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
notifications.error(err)
|
notifications.error("Error previewing query")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,9 +83,8 @@
|
||||||
saveId = _id
|
saveId = _id
|
||||||
notifications.success(`Query saved successfully.`)
|
notifications.success(`Query saved successfully.`)
|
||||||
$goto(`../${_id}`)
|
$goto(`../${_id}`)
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
console.error(err)
|
notifications.error("Error creating query")
|
||||||
notifications.error(`Error creating query. ${err.message}`)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -112,14 +112,13 @@
|
||||||
const { _id } = await queries.save(toSave.datasourceId, toSave)
|
const { _id } = await queries.save(toSave.datasourceId, toSave)
|
||||||
saveId = _id
|
saveId = _id
|
||||||
query = getSelectedQuery()
|
query = getSelectedQuery()
|
||||||
notifications.success(`Request saved successfully.`)
|
notifications.success(`Request saved successfully`)
|
||||||
|
|
||||||
if (dynamicVariables) {
|
if (dynamicVariables) {
|
||||||
datasource.config.dynamicVariables = rebuildVariables(saveId)
|
datasource.config.dynamicVariables = rebuildVariables(saveId)
|
||||||
datasource = await datasources.save(datasource)
|
datasource = await datasources.save(datasource)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error(`Error saving query. ${err.message}`)
|
notifications.error(`Error saving query`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,14 +126,14 @@
|
||||||
try {
|
try {
|
||||||
response = await queries.preview(buildQuery(query))
|
response = await queries.preview(buildQuery(query))
|
||||||
if (response.rows.length === 0) {
|
if (response.rows.length === 0) {
|
||||||
notifications.info("Request did not return any data.")
|
notifications.info("Request did not return any data")
|
||||||
} else {
|
} else {
|
||||||
response.info = response.info || { code: 200 }
|
response.info = response.info || { code: 200 }
|
||||||
schema = response.schema
|
schema = response.schema
|
||||||
notifications.success("Request sent successfully.")
|
notifications.success("Request sent successfully")
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
notifications.error(err)
|
notifications.error("Error running query")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +225,24 @@
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateFlag = async (flag, value) => {
|
||||||
|
try {
|
||||||
|
await flags.updateFlag(flag, value)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error updating flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
query = getSelectedQuery()
|
query = getSelectedQuery()
|
||||||
// clear any unsaved changes to the datasource
|
|
||||||
|
try {
|
||||||
|
// Clear any unsaved changes to the datasource
|
||||||
await datasources.init()
|
await datasources.init()
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error getting datasources")
|
||||||
|
}
|
||||||
|
|
||||||
datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
||||||
const datasourceUrl = datasource?.config.url
|
const datasourceUrl = datasource?.config.url
|
||||||
const qs = query?.fields.queryString
|
const qs = query?.fields.queryString
|
||||||
|
@ -393,8 +406,7 @@
|
||||||
window.open(
|
window.open(
|
||||||
"https://docs.budibase.com/building-apps/data/transformers"
|
"https://docs.budibase.com/building-apps/data/transformers"
|
||||||
)}
|
)}
|
||||||
on:change={() =>
|
on:change={() => updateFlag("queryTransformerBanner", true)}
|
||||||
flags.updateFlag("queryTransformerBanner", true)}
|
|
||||||
>
|
>
|
||||||
Add a JavaScript function to transform the query result.
|
Add a JavaScript function to transform the query result.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { queries, tables, views } from "./"
|
import { queries, tables, views } from "./"
|
||||||
import api from "../../builderStore/api"
|
import { API } from "api"
|
||||||
|
|
||||||
export const INITIAL_DATASOURCE_VALUES = {
|
export const INITIAL_DATASOURCE_VALUES = {
|
||||||
list: [],
|
list: [],
|
||||||
|
@ -13,23 +13,20 @@ export function createDatasourcesStore() {
|
||||||
const { subscribe, update, set } = store
|
const { subscribe, update, set } = store
|
||||||
|
|
||||||
async function updateDatasource(response) {
|
async function updateDatasource(response) {
|
||||||
if (response.status !== 200) {
|
const { datasource, error } = response
|
||||||
throw new Error(await response.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
const { datasource, error } = await response.json()
|
|
||||||
update(state => {
|
update(state => {
|
||||||
const currentIdx = state.list.findIndex(ds => ds._id === datasource._id)
|
const currentIdx = state.list.findIndex(ds => ds._id === datasource._id)
|
||||||
|
|
||||||
const sources = state.list
|
const sources = state.list
|
||||||
|
|
||||||
if (currentIdx >= 0) {
|
if (currentIdx >= 0) {
|
||||||
sources.splice(currentIdx, 1, datasource)
|
sources.splice(currentIdx, 1, datasource)
|
||||||
} else {
|
} else {
|
||||||
sources.push(datasource)
|
sources.push(datasource)
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
return { list: sources, selected: datasource._id, schemaError: error }
|
list: sources,
|
||||||
|
selected: datasource._id,
|
||||||
|
schemaError: error,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return datasource
|
return datasource
|
||||||
}
|
}
|
||||||
|
@ -38,25 +35,25 @@ export function createDatasourcesStore() {
|
||||||
subscribe,
|
subscribe,
|
||||||
update,
|
update,
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const response = await api.get(`/api/datasources`)
|
const datasources = await API.getDatasources()
|
||||||
const json = await response.json()
|
set({
|
||||||
set({ list: json, selected: null })
|
list: datasources,
|
||||||
|
selected: null,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const response = await api.get(`/api/datasources`)
|
const datasources = await API.getDatasources()
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
// Clear selected if it no longer exists, otherwise keep it
|
// Clear selected if it no longer exists, otherwise keep it
|
||||||
const selected = get(store).selected
|
const selected = get(store).selected
|
||||||
let nextSelected = null
|
let nextSelected = null
|
||||||
if (selected && json.find(source => source._id === selected)) {
|
if (selected && datasources.find(source => source._id === selected)) {
|
||||||
nextSelected = selected
|
nextSelected = selected
|
||||||
}
|
}
|
||||||
|
|
||||||
update(state => ({ ...state, list: json, selected: nextSelected }))
|
update(state => ({ ...state, list: datasources, selected: nextSelected }))
|
||||||
return json
|
|
||||||
},
|
},
|
||||||
select: async datasourceId => {
|
select: datasourceId => {
|
||||||
update(state => ({ ...state, selected: datasourceId }))
|
update(state => ({ ...state, selected: datasourceId }))
|
||||||
queries.unselect()
|
queries.unselect()
|
||||||
tables.unselect()
|
tables.unselect()
|
||||||
|
@ -66,37 +63,33 @@ export function createDatasourcesStore() {
|
||||||
update(state => ({ ...state, selected: null }))
|
update(state => ({ ...state, selected: null }))
|
||||||
},
|
},
|
||||||
updateSchema: async datasource => {
|
updateSchema: async datasource => {
|
||||||
let url = `/api/datasources/${datasource._id}/schema`
|
const response = await API.buildDatasourceSchema(datasource?._id)
|
||||||
|
return await updateDatasource(response)
|
||||||
const response = await api.post(url)
|
|
||||||
return updateDatasource(response)
|
|
||||||
},
|
},
|
||||||
save: async (body, fetchSchema = false) => {
|
save: async (body, fetchSchema = false) => {
|
||||||
let response
|
let response
|
||||||
if (body._id) {
|
if (body._id) {
|
||||||
response = await api.put(`/api/datasources/${body._id}`, body)
|
response = await API.updateDatasource(body)
|
||||||
} else {
|
} else {
|
||||||
response = await api.post("/api/datasources", {
|
response = await API.createDatasource({
|
||||||
datasource: body,
|
datasource: body,
|
||||||
fetchSchema,
|
fetchSchema,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateDatasource(response)
|
return updateDatasource(response)
|
||||||
},
|
},
|
||||||
delete: async datasource => {
|
delete: async datasource => {
|
||||||
const response = await api.delete(
|
await API.deleteDatasource({
|
||||||
`/api/datasources/${datasource._id}/${datasource._rev}`
|
datasourceId: datasource?._id,
|
||||||
)
|
datasourceRev: datasource?._rev,
|
||||||
|
})
|
||||||
update(state => {
|
update(state => {
|
||||||
const sources = state.list.filter(
|
const sources = state.list.filter(
|
||||||
existing => existing._id !== datasource._id
|
existing => existing._id !== datasource._id
|
||||||
)
|
)
|
||||||
return { list: sources, selected: null }
|
return { list: sources, selected: null }
|
||||||
})
|
})
|
||||||
|
|
||||||
await queries.fetch()
|
await queries.fetch()
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
removeSchemaError: () => {
|
removeSchemaError: () => {
|
||||||
update(state => {
|
update(state => {
|
||||||
|
|
|
@ -1,37 +1,27 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
|
|
||||||
export function createFlagsStore() {
|
export function createFlagsStore() {
|
||||||
const { subscribe, set } = writable({})
|
const { subscribe, set } = writable({})
|
||||||
|
|
||||||
return {
|
const actions = {
|
||||||
subscribe,
|
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const { doc, response } = await getFlags()
|
const flags = await API.getFlags()
|
||||||
set(doc)
|
set(flags)
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
updateFlag: async (flag, value) => {
|
updateFlag: async (flag, value) => {
|
||||||
const response = await api.post("/api/users/flags", {
|
await API.updateFlag({
|
||||||
flag,
|
flag,
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
if (response.status === 200) {
|
await actions.fetch()
|
||||||
const { doc } = await getFlags()
|
|
||||||
set(doc)
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async function getFlags() {
|
return {
|
||||||
const response = await api.get("/api/users/flags")
|
subscribe,
|
||||||
let doc = {}
|
...actions,
|
||||||
if (response.status === 200) {
|
|
||||||
doc = await response.json()
|
|
||||||
}
|
}
|
||||||
return { doc, response }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const flags = createFlagsStore()
|
export const flags = createFlagsStore()
|
||||||
|
|
|
@ -7,12 +7,8 @@ const createIntegrationsStore = () => {
|
||||||
return {
|
return {
|
||||||
...store,
|
...store,
|
||||||
init: async () => {
|
init: async () => {
|
||||||
try {
|
|
||||||
const integrations = await API.getIntegrations()
|
const integrations = await API.getIntegrations()
|
||||||
store.set(integrations)
|
store.set(integrations)
|
||||||
} catch (error) {
|
|
||||||
store.set(null)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
|
|
||||||
export function createPermissionStore() {
|
export function createPermissionStore() {
|
||||||
const { subscribe } = writable([])
|
const { subscribe } = writable([])
|
||||||
|
@ -7,14 +7,14 @@ export function createPermissionStore() {
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
save: async ({ level, role, resource }) => {
|
save: async ({ level, role, resource }) => {
|
||||||
const response = await api.post(
|
return await API.updatePermissionForResource({
|
||||||
`/api/permission/${role}/${resource}/${level}`
|
resourceId: resource,
|
||||||
)
|
roleId: role,
|
||||||
return await response.json()
|
level,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
forResource: async resourceId => {
|
forResource: async resourceId => {
|
||||||
const response = await api.get(`/api/permission/${resourceId}`)
|
return await API.getPermissionForResource(resourceId)
|
||||||
return await response.json()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { datasources, integrations, tables, views } from "./"
|
import { datasources, integrations, tables, views } from "./"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
import { duplicateName } from "../../helpers/duplicate"
|
import { duplicateName } from "../../helpers/duplicate"
|
||||||
|
|
||||||
const sortQueries = queryList => {
|
const sortQueries = queryList => {
|
||||||
|
@ -15,23 +15,26 @@ export function createQueriesStore() {
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const response = await api.get(`/api/queries`)
|
const queries = await API.getQueries()
|
||||||
const json = await response.json()
|
set({
|
||||||
set({ list: json, selected: null })
|
list: queries,
|
||||||
|
selected: null,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const response = await api.get(`/api/queries`)
|
const queries = await API.getQueries()
|
||||||
const json = await response.json()
|
sortQueries(queries)
|
||||||
sortQueries(json)
|
update(state => ({
|
||||||
update(state => ({ ...state, list: json }))
|
...state,
|
||||||
return json
|
list: queries,
|
||||||
|
}))
|
||||||
},
|
},
|
||||||
save: async (datasourceId, query) => {
|
save: async (datasourceId, query) => {
|
||||||
const _integrations = get(integrations)
|
const _integrations = get(integrations)
|
||||||
const dataSource = get(datasources).list.filter(
|
const dataSource = get(datasources).list.filter(
|
||||||
ds => ds._id === datasourceId
|
ds => ds._id === datasourceId
|
||||||
)
|
)
|
||||||
// check if readable attribute is found
|
// Check if readable attribute is found
|
||||||
if (dataSource.length !== 0) {
|
if (dataSource.length !== 0) {
|
||||||
const integration = _integrations[dataSource[0].source]
|
const integration = _integrations[dataSource[0].source]
|
||||||
const readable = integration.query[query.queryVerb].readable
|
const readable = integration.query[query.queryVerb].readable
|
||||||
|
@ -40,34 +43,28 @@ export function createQueriesStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
query.datasourceId = datasourceId
|
query.datasourceId = datasourceId
|
||||||
const response = await api.post(`/api/queries`, query)
|
const savedQuery = await API.saveQuery(query)
|
||||||
if (response.status !== 200) {
|
|
||||||
throw new Error("Failed saving query.")
|
|
||||||
}
|
|
||||||
const json = await response.json()
|
|
||||||
update(state => {
|
update(state => {
|
||||||
const currentIdx = state.list.findIndex(query => query._id === json._id)
|
const idx = state.list.findIndex(query => query._id === savedQuery._id)
|
||||||
|
|
||||||
const queries = state.list
|
const queries = state.list
|
||||||
|
if (idx >= 0) {
|
||||||
if (currentIdx >= 0) {
|
queries.splice(idx, 1, savedQuery)
|
||||||
queries.splice(currentIdx, 1, json)
|
|
||||||
} else {
|
} else {
|
||||||
queries.push(json)
|
queries.push(savedQuery)
|
||||||
}
|
}
|
||||||
sortQueries(queries)
|
sortQueries(queries)
|
||||||
return { list: queries, selected: json._id }
|
return {
|
||||||
})
|
list: queries,
|
||||||
return json
|
selected: savedQuery._id,
|
||||||
},
|
|
||||||
import: async body => {
|
|
||||||
const response = await api.post(`/api/queries/import`, body)
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
throw new Error(response.message)
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
return response.json()
|
return savedQuery
|
||||||
|
},
|
||||||
|
import: async (data, datasourceId) => {
|
||||||
|
return await API.importQueries({
|
||||||
|
datasourceId,
|
||||||
|
data,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
select: query => {
|
select: query => {
|
||||||
update(state => ({ ...state, selected: query._id }))
|
update(state => ({ ...state, selected: query._id }))
|
||||||
|
@ -79,48 +76,37 @@ export function createQueriesStore() {
|
||||||
update(state => ({ ...state, selected: null }))
|
update(state => ({ ...state, selected: null }))
|
||||||
},
|
},
|
||||||
preview: async query => {
|
preview: async query => {
|
||||||
const response = await api.post("/api/queries/preview", {
|
const parameters = query.parameters.reduce(
|
||||||
fields: query.fields,
|
|
||||||
queryVerb: query.queryVerb,
|
|
||||||
transformer: query.transformer,
|
|
||||||
parameters: query.parameters.reduce(
|
|
||||||
(acc, next) => ({
|
(acc, next) => ({
|
||||||
...acc,
|
...acc,
|
||||||
[next.name]: next.default,
|
[next.name]: next.default,
|
||||||
}),
|
}),
|
||||||
{}
|
{}
|
||||||
),
|
)
|
||||||
datasourceId: query.datasourceId,
|
const result = await API.previewQuery({
|
||||||
queryId: query._id || undefined,
|
...query,
|
||||||
|
parameters,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await response.text()
|
|
||||||
throw `Query error: ${error}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const json = await response.json()
|
|
||||||
// Assume all the fields are strings and create a basic schema from the
|
// Assume all the fields are strings and create a basic schema from the
|
||||||
// unique fields returned by the server
|
// unique fields returned by the server
|
||||||
const schema = {}
|
const schema = {}
|
||||||
for (let field of json.schemaFields) {
|
for (let field of result.schemaFields) {
|
||||||
schema[field] = "string"
|
schema[field] = "string"
|
||||||
}
|
}
|
||||||
return { ...json, schema, rows: json.rows || [] }
|
return { ...result, schema, rows: result.rows || [] }
|
||||||
},
|
},
|
||||||
delete: async query => {
|
delete: async query => {
|
||||||
const response = await api.delete(
|
await API.deleteQuery({
|
||||||
`/api/queries/${query._id}/${query._rev}`
|
queryId: query?._id,
|
||||||
)
|
queryRev: query?._rev,
|
||||||
|
})
|
||||||
update(state => {
|
update(state => {
|
||||||
state.list = state.list.filter(existing => existing._id !== query._id)
|
state.list = state.list.filter(existing => existing._id !== query._id)
|
||||||
if (state.selected === query._id) {
|
if (state.selected === query._id) {
|
||||||
state.selected = null
|
state.selected = null
|
||||||
}
|
}
|
||||||
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
duplicate: async query => {
|
duplicate: async query => {
|
||||||
let list = get(store).list
|
let list = get(store).list
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
|
|
||||||
export function createRolesStore() {
|
export function createRolesStore() {
|
||||||
const { subscribe, update, set } = writable([])
|
const { subscribe, update, set } = writable([])
|
||||||
|
|
||||||
return {
|
const actions = {
|
||||||
subscribe,
|
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
set(await getRoles())
|
const roles = await API.getRoles()
|
||||||
|
set(roles)
|
||||||
},
|
},
|
||||||
delete: async role => {
|
delete: async role => {
|
||||||
const response = await api.delete(`/api/roles/${role._id}/${role._rev}`)
|
await API.deleteRole({
|
||||||
|
roleId: role?._id,
|
||||||
|
roleRev: role?._rev,
|
||||||
|
})
|
||||||
update(state => state.filter(existing => existing._id !== role._id))
|
update(state => state.filter(existing => existing._id !== role._id))
|
||||||
return response
|
|
||||||
},
|
},
|
||||||
save: async role => {
|
save: async role => {
|
||||||
const response = await api.post("/api/roles", role)
|
const savedRole = await API.saveRole(role)
|
||||||
set(await getRoles())
|
await actions.fetch()
|
||||||
return response
|
return savedRole
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
...actions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getRoles() {
|
|
||||||
const response = await api.get("/api/roles")
|
|
||||||
return await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export const roles = createRolesStore()
|
export const roles = createRolesStore()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { get, writable } from "svelte/store"
|
import { get, writable } from "svelte/store"
|
||||||
import { datasources, queries, views } from "./"
|
import { datasources, queries, views } from "./"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
import { SWITCHABLE_TYPES } from "../../constants/backend"
|
import { SWITCHABLE_TYPES } from "../../constants/backend"
|
||||||
|
|
||||||
export function createTablesStore() {
|
export function createTablesStore() {
|
||||||
|
@ -9,10 +9,11 @@ export function createTablesStore() {
|
||||||
const { subscribe, update, set } = store
|
const { subscribe, update, set } = store
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
const tablesResponse = await api.get(`/api/tables`)
|
const tables = await API.getTables()
|
||||||
const tables = await tablesResponse.json()
|
update(state => ({
|
||||||
update(state => ({ ...state, list: tables }))
|
...state,
|
||||||
return tables
|
list: tables,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function select(table) {
|
async function select(table) {
|
||||||
|
@ -38,16 +39,16 @@ export function createTablesStore() {
|
||||||
const oldTable = get(store).list.filter(t => t._id === table._id)[0]
|
const oldTable = get(store).list.filter(t => t._id === table._id)[0]
|
||||||
|
|
||||||
const fieldNames = []
|
const fieldNames = []
|
||||||
// update any renamed schema keys to reflect their names
|
// Update any renamed schema keys to reflect their names
|
||||||
for (let key of Object.keys(updatedTable.schema)) {
|
for (let key of Object.keys(updatedTable.schema)) {
|
||||||
// if field name has been seen before remove it
|
// If field name has been seen before remove it
|
||||||
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
|
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
|
||||||
delete updatedTable.schema[key]
|
delete updatedTable.schema[key]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const field = updatedTable.schema[key]
|
const field = updatedTable.schema[key]
|
||||||
const oldField = oldTable?.schema[key]
|
const oldField = oldTable?.schema[key]
|
||||||
// if the type has changed then revert back to the old field
|
// If the type has changed then revert back to the old field
|
||||||
if (
|
if (
|
||||||
oldField != null &&
|
oldField != null &&
|
||||||
oldField?.type !== field.type &&
|
oldField?.type !== field.type &&
|
||||||
|
@ -55,21 +56,17 @@ export function createTablesStore() {
|
||||||
) {
|
) {
|
||||||
updatedTable.schema[key] = oldField
|
updatedTable.schema[key] = oldField
|
||||||
}
|
}
|
||||||
// field has been renamed
|
// Field has been renamed
|
||||||
if (field.name && field.name !== key) {
|
if (field.name && field.name !== key) {
|
||||||
updatedTable.schema[field.name] = field
|
updatedTable.schema[field.name] = field
|
||||||
updatedTable._rename = { old: key, updated: field.name }
|
updatedTable._rename = { old: key, updated: field.name }
|
||||||
delete updatedTable.schema[key]
|
delete updatedTable.schema[key]
|
||||||
}
|
}
|
||||||
// finally record this field has been used
|
// Finally record this field has been used
|
||||||
fieldNames.push(key.toLowerCase())
|
fieldNames.push(key.toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await api.post(`/api/tables`, updatedTable)
|
const savedTable = await API.saveTable(updatedTable)
|
||||||
if (response.status !== 200) {
|
|
||||||
throw (await response.json()).message
|
|
||||||
}
|
|
||||||
const savedTable = await response.json()
|
|
||||||
await fetch()
|
await fetch()
|
||||||
if (table.type === "external") {
|
if (table.type === "external") {
|
||||||
await datasources.fetch()
|
await datasources.fetch()
|
||||||
|
@ -91,21 +88,18 @@ export function createTablesStore() {
|
||||||
},
|
},
|
||||||
save,
|
save,
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const response = await api.get("/api/tables")
|
const tables = await API.getTables()
|
||||||
const json = await response.json()
|
|
||||||
set({
|
set({
|
||||||
list: json,
|
list: tables,
|
||||||
selected: {},
|
selected: {},
|
||||||
draft: {},
|
draft: {},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
delete: async table => {
|
delete: async table => {
|
||||||
const response = await api.delete(
|
await API.deleteTable({
|
||||||
`/api/tables/${table._id}/${table._rev}`
|
tableId: table?._id,
|
||||||
)
|
tableRev: table?._rev,
|
||||||
if (response.status !== 200) {
|
})
|
||||||
throw (await response.json()).message
|
|
||||||
}
|
|
||||||
update(state => ({
|
update(state => ({
|
||||||
...state,
|
...state,
|
||||||
list: state.list.filter(existing => existing._id !== table._id),
|
list: state.list.filter(existing => existing._id !== table._id),
|
||||||
|
@ -156,12 +150,16 @@ export function createTablesStore() {
|
||||||
await promise
|
await promise
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteField: field => {
|
deleteField: async field => {
|
||||||
|
let promise
|
||||||
update(state => {
|
update(state => {
|
||||||
delete state.draft.schema[field.name]
|
delete state.draft.schema[field.name]
|
||||||
save(state.draft)
|
promise = save(state.draft)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
if (promise) {
|
||||||
|
await promise
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { tables, datasources, queries } from "./"
|
import { tables, datasources, queries } from "./"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
|
|
||||||
export function createViewsStore() {
|
export function createViewsStore() {
|
||||||
const { subscribe, update } = writable({
|
const { subscribe, update } = writable({
|
||||||
|
@ -11,7 +11,7 @@ export function createViewsStore() {
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
update,
|
update,
|
||||||
select: async view => {
|
select: view => {
|
||||||
update(state => ({
|
update(state => ({
|
||||||
...state,
|
...state,
|
||||||
selected: view,
|
selected: view,
|
||||||
|
@ -27,16 +27,14 @@ export function createViewsStore() {
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
delete: async view => {
|
delete: async view => {
|
||||||
await api.delete(`/api/views/${view}`)
|
await API.deleteView(view)
|
||||||
await tables.fetch()
|
await tables.fetch()
|
||||||
},
|
},
|
||||||
save: async view => {
|
save: async view => {
|
||||||
const response = await api.post(`/api/views`, view)
|
const savedView = await API.saveView(view)
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
const viewMeta = {
|
const viewMeta = {
|
||||||
name: view.name,
|
name: view.name,
|
||||||
...json,
|
...savedView,
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewTable = get(tables).list.find(
|
const viewTable = get(tables).list.find(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
export function createEmailStore() {
|
export function createEmailStore() {
|
||||||
const store = writable({})
|
const store = writable({})
|
||||||
|
@ -8,34 +9,35 @@ export function createEmailStore() {
|
||||||
subscribe: store.subscribe,
|
subscribe: store.subscribe,
|
||||||
templates: {
|
templates: {
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
// fetch the email template definitions
|
try {
|
||||||
const response = await api.get(`/api/global/template/definitions`)
|
// fetch the email template definitions and templates
|
||||||
const definitions = await response.json()
|
const definitions = await API.getEmailTemplateDefinitions()
|
||||||
|
const templates = await API.getEmailTemplates()
|
||||||
// fetch the email templates themselves
|
|
||||||
const templatesResponse = await api.get(`/api/global/template/email`)
|
|
||||||
const templates = await templatesResponse.json()
|
|
||||||
|
|
||||||
store.set({
|
store.set({
|
||||||
definitions,
|
definitions,
|
||||||
templates,
|
templates,
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching email templates")
|
||||||
|
store.set({})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
save: async template => {
|
save: async template => {
|
||||||
|
try {
|
||||||
// Save your template config
|
// Save your template config
|
||||||
const response = await api.post(`/api/global/template`, template)
|
const savedTemplate = await API.saveEmailTemplate(template)
|
||||||
const json = await response.json()
|
template._rev = savedTemplate._rev
|
||||||
if (response.status !== 200) throw new Error(json.message)
|
template._id = savedTemplate._id
|
||||||
template._rev = json._rev
|
|
||||||
template._id = json._id
|
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const currentIdx = state.templates.findIndex(
|
const currentIdx = state.templates.findIndex(
|
||||||
template => template.purpose === json.purpose
|
template => template.purpose === savedTemplate.purpose
|
||||||
)
|
)
|
||||||
state.templates.splice(currentIdx, 1, template)
|
state.templates.splice(currentIdx, 1, template)
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error saving email template")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
export const buildDatasourceEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Gets a list of datasources.
|
||||||
|
*/
|
||||||
|
getDatasources: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/datasources",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the server to build the schema for a datasource.
|
||||||
|
* @param datasourceId the datasource ID to build the schema for
|
||||||
|
*/
|
||||||
|
buildDatasourceSchema: async datasourceId => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/datasources/${datasourceId}/schema`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a datasource
|
||||||
|
* @param datasource the datasource to create
|
||||||
|
* @param fetchSchema whether to fetch the schema or not
|
||||||
|
*/
|
||||||
|
createDatasource: async ({ datasource, fetchSchema }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/datasources",
|
||||||
|
body: {
|
||||||
|
datasource,
|
||||||
|
fetchSchema,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a datasource
|
||||||
|
* @param datasource the datasource to update
|
||||||
|
*/
|
||||||
|
updateDatasource: async datasource => {
|
||||||
|
return await API.put({
|
||||||
|
url: `/api/datasources/${datasource._id}`,
|
||||||
|
body: datasource,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a datasource.
|
||||||
|
* @param datasourceId the ID of the ddtasource to delete
|
||||||
|
* @param datasourceRev the rev of the datasource to delete
|
||||||
|
*/
|
||||||
|
deleteDatasource: async ({ datasourceId, datasourceRev }) => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/datasources/${datasourceId}/${datasourceRev}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,25 @@
|
||||||
|
export const buildFlagEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Gets the current user flags object.
|
||||||
|
*/
|
||||||
|
getFlags: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/users/flags",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a flag for the current user.
|
||||||
|
* @param flag the flag to update
|
||||||
|
* @param value the value to set the flag to
|
||||||
|
*/
|
||||||
|
updateFlag: async ({ flag, value }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/users/flags",
|
||||||
|
body: {
|
||||||
|
flag,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -4,13 +4,18 @@ import { buildAppEndpoints } from "./app"
|
||||||
import { buildAttachmentEndpoints } from "./attachments"
|
import { buildAttachmentEndpoints } from "./attachments"
|
||||||
import { buildAuthEndpoints } from "./auth"
|
import { buildAuthEndpoints } from "./auth"
|
||||||
import { buildAutomationEndpoints } from "./automations"
|
import { buildAutomationEndpoints } from "./automations"
|
||||||
|
import { buildDatasourceEndpoints } from "./datasources"
|
||||||
|
import { buildFlagEndpoints } from "./flags"
|
||||||
import { buildHostingEndpoints } from "./hosting"
|
import { buildHostingEndpoints } from "./hosting"
|
||||||
|
import { buildPermissionsEndpoints } from "./permissions"
|
||||||
import { buildQueryEndpoints } from "./queries"
|
import { buildQueryEndpoints } from "./queries"
|
||||||
import { buildRelationshipEndpoints } from "./relationships"
|
import { buildRelationshipEndpoints } from "./relationships"
|
||||||
|
import { buildRoleEndpoints } from "./roles"
|
||||||
import { buildRouteEndpoints } from "./routes"
|
import { buildRouteEndpoints } from "./routes"
|
||||||
import { buildRowEndpoints } from "./rows"
|
import { buildRowEndpoints } from "./rows"
|
||||||
import { buildScreenEndpoints } from "./screens"
|
import { buildScreenEndpoints } from "./screens"
|
||||||
import { buildTableEndpoints } from "./tables"
|
import { buildTableEndpoints } from "./tables"
|
||||||
|
import { buildTemplateEndpoints } from "./templates"
|
||||||
import { buildViewEndpoints } from "./views"
|
import { buildViewEndpoints } from "./views"
|
||||||
|
|
||||||
const defaultAPIClientConfig = {
|
const defaultAPIClientConfig = {
|
||||||
|
@ -184,13 +189,18 @@ export const createAPIClient = config => {
|
||||||
...buildAttachmentEndpoints(API),
|
...buildAttachmentEndpoints(API),
|
||||||
...buildAuthEndpoints(API),
|
...buildAuthEndpoints(API),
|
||||||
...buildAutomationEndpoints(API),
|
...buildAutomationEndpoints(API),
|
||||||
|
...buildDatasourceEndpoints(API),
|
||||||
|
...buildFlagEndpoints(API),
|
||||||
...buildHostingEndpoints(API),
|
...buildHostingEndpoints(API),
|
||||||
|
...buildPermissionsEndpoints(API),
|
||||||
...buildQueryEndpoints(API),
|
...buildQueryEndpoints(API),
|
||||||
...buildRelationshipEndpoints(API),
|
...buildRelationshipEndpoints(API),
|
||||||
|
...buildRoleEndpoints(API),
|
||||||
...buildRouteEndpoints(API),
|
...buildRouteEndpoints(API),
|
||||||
...buildRowEndpoints(API),
|
...buildRowEndpoints(API),
|
||||||
...buildScreenEndpoints(API),
|
...buildScreenEndpoints(API),
|
||||||
...buildTableEndpoints(API),
|
...buildTableEndpoints(API),
|
||||||
|
...buildTemplateEndpoints(API),
|
||||||
...buildViewEndpoints(API),
|
...buildViewEndpoints(API),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
export const buildPermissionsEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Gets the permission required to access a specific resource
|
||||||
|
* @param resourceId the resource ID to check
|
||||||
|
*/
|
||||||
|
getPermissionForResource: async resourceId => {
|
||||||
|
return await API.get({
|
||||||
|
url: `/api/permission/${resourceId}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the permissions for a certain resource
|
||||||
|
* @param resourceId the ID of the resource to update
|
||||||
|
* @param roleId the ID of the role to update the permissions of
|
||||||
|
* @param level the level to assign the role for this resource
|
||||||
|
* @return {Promise<*>}
|
||||||
|
*/
|
||||||
|
updatePermissionForResource: async ({ resourceId, roleId, level }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/permission/${roleId}/${resourceId}/${level}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,6 +1,9 @@
|
||||||
export const buildQueryEndpoints = API => ({
|
export const buildQueryEndpoints = API => ({
|
||||||
/**
|
/**
|
||||||
* Executes a query against an external data connector.
|
* Executes a query against an external data connector.
|
||||||
|
* @param queryId the ID of the query to execute
|
||||||
|
* @param pagination pagination info for the query
|
||||||
|
* @param parameters parameters for the query
|
||||||
*/
|
*/
|
||||||
executeQuery: async ({ queryId, pagination, parameters }) => {
|
executeQuery: async ({ queryId, pagination, parameters }) => {
|
||||||
return await API.post({
|
return await API.post({
|
||||||
|
@ -14,6 +17,7 @@ export const buildQueryEndpoints = API => ({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the definition of an external query.
|
* Fetches the definition of an external query.
|
||||||
|
* @param queryId the ID of thr query to fetch the definition of
|
||||||
*/
|
*/
|
||||||
fetchQueryDefinition: async queryId => {
|
fetchQueryDefinition: async queryId => {
|
||||||
return await API.get({
|
return await API.get({
|
||||||
|
@ -21,4 +25,61 @@ export const buildQueryEndpoints = API => ({
|
||||||
cache: true,
|
cache: true,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of queries
|
||||||
|
*/
|
||||||
|
getQueries: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/queries",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a query.
|
||||||
|
* @param query the query to save
|
||||||
|
*/
|
||||||
|
saveQuery: async query => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/queries",
|
||||||
|
body: query,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a query
|
||||||
|
* @param queryId the ID of the query to delete
|
||||||
|
* @param queryRev the rev of the query to delete
|
||||||
|
*/
|
||||||
|
deleteQuery: async ({ queryId, queryRev }) => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/queries/${queryId}/${queryRev}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a set of queries into a certain datasource
|
||||||
|
* @param datasourceId the datasource ID to import queries into
|
||||||
|
* @param data the data string of the content to import
|
||||||
|
*/
|
||||||
|
importQueries: async ({ datasourceId, data }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/queries/import",
|
||||||
|
body: {
|
||||||
|
datasourceId,
|
||||||
|
data,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a query with test parameters to see the result.
|
||||||
|
* @param query the query to run
|
||||||
|
*/
|
||||||
|
previewQuery: async query => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/queries/preview",
|
||||||
|
body: query,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
export const buildRoleEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Deletes a role.
|
||||||
|
* @param roleId the ID of the role to delete
|
||||||
|
* @param roleRev the rev of the role to delete
|
||||||
|
*/
|
||||||
|
deleteRole: async ({ roleId, roleRev }) => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/roles/${roleId}/${roleRev}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a role.
|
||||||
|
* @param role the role to save
|
||||||
|
*/
|
||||||
|
saveRole: async role => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/roles",
|
||||||
|
body: role,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of roles.
|
||||||
|
*/
|
||||||
|
getRoles: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/roles",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -79,4 +79,35 @@ export const buildTableEndpoints = API => ({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list o tables.
|
||||||
|
*/
|
||||||
|
getTables: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/tables",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a table.
|
||||||
|
* @param table the table to save
|
||||||
|
*/
|
||||||
|
saveTable: async table => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/tables",
|
||||||
|
body: table,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a table.
|
||||||
|
* @param tableId the ID of the table to delete
|
||||||
|
* @param tableRev the rev of the table to delete
|
||||||
|
*/
|
||||||
|
deleteTable: async ({ tableId, tableRev }) => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/tables/${tableId}/${tableRev}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
export const buildTemplateEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Gets the list of email template definitions.
|
||||||
|
*/
|
||||||
|
getEmailTemplateDefinitions: async () => {
|
||||||
|
return await API.get({ url: "/api/global/template/definitions" })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of email templates.
|
||||||
|
*/
|
||||||
|
getEmailTemplates: async () => {
|
||||||
|
return await API.get({ url: "/api/global/template/email" })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves an email template.
|
||||||
|
* @param template the template to save
|
||||||
|
*/
|
||||||
|
saveEmailTemplate: async template => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/global/template",
|
||||||
|
body: {
|
||||||
|
template,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,6 +1,10 @@
|
||||||
export const buildViewEndpoints = API => ({
|
export const buildViewEndpoints = API => ({
|
||||||
/**
|
/**
|
||||||
* Fetches all rows in a view.
|
* Fetches all rows in a view
|
||||||
|
* @param name the name of the view
|
||||||
|
* @param field the field to perform the calculation on
|
||||||
|
* @param groupBy the field to group by
|
||||||
|
* @param calculation the calculation to perform
|
||||||
*/
|
*/
|
||||||
fetchViewData: async ({ name, field, groupBy, calculation }) => {
|
fetchViewData: async ({ name, field, groupBy, calculation }) => {
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
|
@ -9,7 +13,7 @@ export const buildViewEndpoints = API => ({
|
||||||
params.set("calculation", calculation)
|
params.set("calculation", calculation)
|
||||||
}
|
}
|
||||||
if (groupBy) {
|
if (groupBy) {
|
||||||
params.set("group", groupBy ? "true" : "false")
|
params.set("group", groupBy)
|
||||||
}
|
}
|
||||||
const QUERY_VIEW_URL = field
|
const QUERY_VIEW_URL = field
|
||||||
? `/api/views/${name}?${params}`
|
? `/api/views/${name}?${params}`
|
||||||
|
@ -31,4 +35,25 @@ export const buildViewEndpoints = API => ({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a view.
|
||||||
|
* @param view the view to save
|
||||||
|
*/
|
||||||
|
saveView: async view => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/views",
|
||||||
|
body: view,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a view.
|
||||||
|
* @param viewName the name of the view to delete
|
||||||
|
*/
|
||||||
|
deleteView: async viewName => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/views/${viewName}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue