diff --git a/packages/builder/src/builderStore/api.js b/packages/builder/src/builderStore/api.js
index bd7cccbc5a..3dd6c28031 100644
--- a/packages/builder/src/builderStore/api.js
+++ b/packages/builder/src/builderStore/api.js
@@ -5,7 +5,6 @@ import {
} from "@budibase/frontend-core"
import { store } from "./index"
import { get } from "svelte/store"
-import { notifications } from "@budibase/bbui"
export const API = createAPIClient({
attachHeaders: headers => {
@@ -25,11 +24,6 @@ export const API = createAPIClient({
return
}
- // Show a notification for any errors
- if (message) {
- notifications.error(`Error fetching ${url}: ${message}`)
- }
-
// Log all errors to console
console.error(`HTTP ${status} on ${method}:${url}:\n\t${message}`)
diff --git a/packages/builder/src/components/backend/DataTable/modals/CalculateModal.svelte b/packages/builder/src/components/backend/DataTable/modals/CalculateModal.svelte
index 50d44eca88..81f54032f6 100644
--- a/packages/builder/src/components/backend/DataTable/modals/CalculateModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/CalculateModal.svelte
@@ -38,9 +38,13 @@
})
function saveView() {
- views.save(view)
- notifications.success(`View ${view.name} saved.`)
- analytics.captureEvent(Events.VIEW.ADDED_CALCULATE, { field: view.field })
+ try {
+ views.save(view)
+ notifications.success(`View ${view.name} saved`)
+ analytics.captureEvent(Events.VIEW.ADDED_CALCULATE, { field: view.field })
+ } catch (error) {
+ notifications.error("Error saving view")
+ }
}
diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte
index 1fa5c6e073..385af3983c 100644
--- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte
@@ -122,7 +122,7 @@
})
dispatch("updatecolumns")
} catch (err) {
- notifications.error(err)
+ notifications.error("Error saving column")
}
}
@@ -131,17 +131,21 @@
}
function deleteColumn() {
- field.name = deleteColName
- if (field.name === $tables.selected.primaryDisplay) {
- notifications.error("You cannot delete the display column")
- } else {
- tables.deleteField(field)
- notifications.success(`Column ${field.name} deleted.`)
- confirmDeleteDialog.hide()
- hide()
- deletion = false
+ try {
+ field.name = deleteColName
+ if (field.name === $tables.selected.primaryDisplay) {
+ notifications.error("You cannot delete the display column")
+ } else {
+ tables.deleteField(field)
+ notifications.success(`Column ${field.name} deleted.`)
+ confirmDeleteDialog.hide()
+ hide()
+ deletion = false
+ dispatch("updatecolumns")
+ }
+ } catch (error) {
+ notifications.error("Error deleting column")
}
- dispatch("updatecolumns")
}
function handleTypeChange(event) {
diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateViewModal.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateViewModal.svelte
index 2f6ec51233..2ea0c1b63b 100644
--- a/packages/builder/src/components/backend/DataTable/modals/CreateViewModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/CreateViewModal.svelte
@@ -12,17 +12,21 @@
function saveView() {
if (views.includes(name)) {
- notifications.error(`View exists with name ${name}.`)
+ notifications.error(`View exists with name ${name}`)
return
}
- viewsStore.save({
- name,
- tableId: $tables.selected._id,
- field,
- })
- notifications.success(`View ${name} created`)
- analytics.captureEvent(Events.VIEW.CREATED, { name })
- $goto(`../../view/${name}`)
+ try {
+ viewsStore.save({
+ name,
+ tableId: $tables.selected._id,
+ field,
+ })
+ notifications.success(`View ${name} created`)
+ analytics.captureEvent(Events.VIEW.CREATED, { name })
+ $goto(`../../view/${name}`)
+ } catch (error) {
+ notifications.error("Error creating view")
+ }
}
diff --git a/packages/builder/src/components/backend/DataTable/modals/FilterModal.svelte b/packages/builder/src/components/backend/DataTable/modals/FilterModal.svelte
index c413ee16ce..1209ea7e5f 100644
--- a/packages/builder/src/components/backend/DataTable/modals/FilterModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/FilterModal.svelte
@@ -72,11 +72,15 @@
$: schema = viewTable && viewTable.schema ? viewTable.schema : {}
function saveView() {
- views.save(view)
- notifications.success(`View ${view.name} saved.`)
- analytics.captureEvent(Events.VIEW.ADDED_FILTER, {
- filters: JSON.stringify(view.filters),
- })
+ try {
+ views.save(view)
+ notifications.success(`View ${view.name} saved`)
+ analytics.captureEvent(Events.VIEW.ADDED_FILTER, {
+ filters: JSON.stringify(view.filters),
+ })
+ } catch (error) {
+ notifcations.error("Error saving view")
+ }
}
function removeFilter(idx) {
diff --git a/packages/builder/src/components/backend/DataTable/modals/GroupByModal.svelte b/packages/builder/src/components/backend/DataTable/modals/GroupByModal.svelte
index b0df0ef1da..59fc4a2c5d 100644
--- a/packages/builder/src/components/backend/DataTable/modals/GroupByModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/GroupByModal.svelte
@@ -19,8 +19,12 @@
.map(([key]) => key)
function saveView() {
- views.save(view)
- notifications.success(`View ${view.name} saved.`)
+ try {
+ views.save(view)
+ notifications.success(`View ${view.name} saved`)
+ } catch (error) {
+ notifications.error("Error saving view")
+ }
}
diff --git a/packages/builder/src/components/backend/DataTable/modals/ManageAccessModal.svelte b/packages/builder/src/components/backend/DataTable/modals/ManageAccessModal.svelte
index 0998a5be2e..aa6dbc93e0 100644
--- a/packages/builder/src/components/backend/DataTable/modals/ManageAccessModal.svelte
+++ b/packages/builder/src/components/backend/DataTable/modals/ManageAccessModal.svelte
@@ -14,15 +14,19 @@
export let permissions
async function changePermission(level, role) {
- await permissionsStore.save({
- level,
- role,
- resource: resourceId,
- })
+ try {
+ await permissionsStore.save({
+ level,
+ role,
+ resource: resourceId,
+ })
- // Show updated permissions in UI: REMOVE
- permissions = await permissionsStore.forResource(resourceId)
- notifications.success("Updated permissions.")
+ // Show updated permissions in UI: REMOVE
+ permissions = await permissionsStore.forResource(resourceId)
+ notifications.success("Updated permissions")
+ } catch (error) {
+ notifications.error("Error updating permissions")
+ }
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
index af345ddcdf..b40686afb5 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/DatasourceNavigator.svelte
@@ -10,6 +10,7 @@
import TableNavigator from "components/backend/TableNavigator/TableNavigator.svelte"
import { customQueryIconText, customQueryIconColor } from "helpers/data/utils"
import ICONS from "./icons"
+ import { notifications } from "@budibase/bbui"
let openDataSources = []
$: enrichedDataSources = Array.isArray($datasources.list)
@@ -64,8 +65,12 @@
}
onMount(() => {
- datasources.fetch()
- queries.fetch()
+ try {
+ datasources.fetch()
+ queries.fetch()
+ } catch (error) {
+ notifications.error("Error fetching datasources and queries")
+ }
})
const containsActiveEntity = datasource => {
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/CreateExternalTableModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/CreateExternalTableModal.svelte
index 52402a0396..f6cd6af758 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/CreateExternalTableModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/CreateExternalTableModal.svelte
@@ -1,5 +1,5 @@
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte
index 819fb32e45..1148695712 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/TableIntegrationMenu/PlusConfigForm.svelte
@@ -90,8 +90,8 @@
await datasources.updateSchema(datasource)
notifications.success(`Datasource ${name} tables updated successfully.`)
await tables.fetch()
- } catch (err) {
- notifications.error(`Error updating datasource schema: ${err}`)
+ } catch (error) {
+ notifications.error("Error updating datasource schema")
}
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
index d1a3d7c302..267b0495ec 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/CreateDatasourceModal.svelte
@@ -62,9 +62,13 @@
externalDatasourceModal.hide()
internalTableModal.show()
} else if (integration.type === IntegrationTypes.REST) {
- // skip modal for rest, create straight away
- const resp = await createRestDatasource(integration)
- $goto(`./datasource/${resp._id}`)
+ try {
+ // Skip modal for rest, create straight away
+ const resp = await createRestDatasource(integration)
+ $goto(`./datasource/${resp._id}`)
+ } catch (error) {
+ notifications.error("Error creating datasource")
+ }
} else {
externalDatasourceModal.show()
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte
index da8c0515b7..06e00ff5d0 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte
@@ -20,7 +20,7 @@
$goto(`./datasource/${resp._id}`)
notifications.success(`Datasource updated successfully.`)
} catch (err) {
- notifications.error(`Error saving datasource: ${err}`)
+ notifications.error("Error saving datasource")
}
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte
index cd6cef42d1..86cc25a0f3 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/ImportRestQueriesModal.svelte
@@ -79,8 +79,8 @@
})
return true
- } catch (err) {
- notifications.error(`Error importing: ${err}`)
+ } catch (error) {
+ notifications.error("Error importing queries")
return false
}
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte
index 1354c31b87..ae0023f682 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditDatasourcePopover.svelte
@@ -12,24 +12,28 @@
let updateDatasourceDialog
async function deleteDatasource() {
- let wasSelectedSource = $datasources.selected
- if (!wasSelectedSource && $queries.selected) {
- const queryId = $queries.selected
- wasSelectedSource = $datasources.list.find(ds =>
- queryId.includes(ds._id)
- )?._id
- }
- const wasSelectedTable = $tables.selected
- await datasources.delete(datasource)
- notifications.success("Datasource deleted")
- // navigate to first index page if the source you are deleting is selected
- const entities = Object.values(datasource?.entities || {})
- if (
- wasSelectedSource === datasource._id ||
- (entities &&
- entities.find(entity => entity._id === wasSelectedTable?._id))
- ) {
- $goto("./datasource")
+ try {
+ let wasSelectedSource = $datasources.selected
+ if (!wasSelectedSource && $queries.selected) {
+ const queryId = $queries.selected
+ wasSelectedSource = $datasources.list.find(ds =>
+ queryId.includes(ds._id)
+ )?._id
+ }
+ const wasSelectedTable = $tables.selected
+ await datasources.delete(datasource)
+ notifications.success("Datasource deleted")
+ // Navigate to first index page if the source you are deleting is selected
+ const entities = Object.values(datasource?.entities || {})
+ if (
+ wasSelectedSource === datasource._id ||
+ (entities &&
+ entities.find(entity => entity._id === wasSelectedTable?._id))
+ ) {
+ $goto("./datasource")
+ }
+ } catch (error) {
+ notifications.error("Error deleting datasource")
}
}
diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte
index b15746735b..e18deab2dd 100644
--- a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte
+++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte
@@ -10,26 +10,30 @@
let confirmDeleteDialog
async function deleteQuery() {
- const wasSelectedQuery = $queries.selected
- // need to calculate this before the query is deleted
- const navigateToDatasource = wasSelectedQuery === query._id
+ try {
+ const wasSelectedQuery = $queries.selected
+ // need to calculate this before the query is deleted
+ const navigateToDatasource = wasSelectedQuery === query._id
- await queries.delete(query)
- await datasources.fetch()
+ await queries.delete(query)
+ await datasources.fetch()
- if (navigateToDatasource) {
- await datasources.select(query.datasourceId)
- $goto(`./datasource/${query.datasourceId}`)
+ if (navigateToDatasource) {
+ await datasources.select(query.datasourceId)
+ $goto(`./datasource/${query.datasourceId}`)
+ }
+ notifications.success("Query deleted")
+ } catch (error) {
+ notifications.error("Error deleting query")
}
- notifications.success("Query deleted")
}
async function duplicateQuery() {
try {
const newQuery = await queries.duplicate(query)
onClickQuery(newQuery)
- } catch (e) {
- notifications.error(e.message)
+ } catch (error) {
+ notifications.error("Error duplicating query")
}
}
diff --git a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte
index 0211a37557..b4035ba6e4 100644
--- a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte
@@ -49,8 +49,8 @@
if (wasSelectedTable && wasSelectedTable._id === table._id) {
$goto("./table")
}
- } catch (err) {
- notifications.error(err)
+ } catch (error) {
+ notifications.error("Error deleting table")
}
}
diff --git a/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte
index 8384fc1d90..0ab5d4326f 100644
--- a/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte
+++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditViewPopover.svelte
@@ -27,11 +27,15 @@
}
async function deleteView() {
- const name = view.name
- const id = view.tableId
- await views.delete(name)
- notifications.success("View deleted")
- $goto(`./table/${id}`)
+ try {
+ const name = view.name
+ const id = view.tableId
+ await views.delete(name)
+ notifications.success("View deleted")
+ $goto(`./table/${id}`)
+ } catch (error) {
+ notifications.error("Error deleting view")
+ }
}
diff --git a/packages/builder/src/components/integration/AccessLevelSelect.svelte b/packages/builder/src/components/integration/AccessLevelSelect.svelte
index 88814ed648..24c1e9b069 100644
--- a/packages/builder/src/components/integration/AccessLevelSelect.svelte
+++ b/packages/builder/src/components/integration/AccessLevelSelect.svelte
@@ -1,5 +1,5 @@
diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte
index 808c3a49ec..85ae8a11f5 100644
--- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/rest/[query]/index.svelte
@@ -112,14 +112,13 @@
const { _id } = await queries.save(toSave.datasourceId, toSave)
saveId = _id
query = getSelectedQuery()
- notifications.success(`Request saved successfully.`)
-
+ notifications.success(`Request saved successfully`)
if (dynamicVariables) {
datasource.config.dynamicVariables = rebuildVariables(saveId)
datasource = await datasources.save(datasource)
}
} catch (err) {
- notifications.error(`Error saving query. ${err.message}`)
+ notifications.error(`Error saving query`)
}
}
@@ -127,14 +126,14 @@
try {
response = await queries.preview(buildQuery(query))
if (response.rows.length === 0) {
- notifications.info("Request did not return any data.")
+ notifications.info("Request did not return any data")
} else {
response.info = response.info || { code: 200 }
schema = response.schema
- notifications.success("Request sent successfully.")
+ notifications.success("Request sent successfully")
}
- } catch (err) {
- notifications.error(err)
+ } catch (error) {
+ 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 () => {
query = getSelectedQuery()
- // clear any unsaved changes to the datasource
- await datasources.init()
+
+ try {
+ // Clear any unsaved changes to the datasource
+ await datasources.init()
+ } catch (error) {
+ notifications.error("Error getting datasources")
+ }
+
datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
const datasourceUrl = datasource?.config.url
const qs = query?.fields.queryString
@@ -393,8 +406,7 @@
window.open(
"https://docs.budibase.com/building-apps/data/transformers"
)}
- on:change={() =>
- flags.updateFlag("queryTransformerBanner", true)}
+ on:change={() => updateFlag("queryTransformerBanner", true)}
>
Add a JavaScript function to transform the query result.
diff --git a/packages/builder/src/stores/backend/datasources.js b/packages/builder/src/stores/backend/datasources.js
index 7810c3a950..2423394c6a 100644
--- a/packages/builder/src/stores/backend/datasources.js
+++ b/packages/builder/src/stores/backend/datasources.js
@@ -1,6 +1,6 @@
import { writable, get } from "svelte/store"
import { queries, tables, views } from "./"
-import api from "../../builderStore/api"
+import { API } from "api"
export const INITIAL_DATASOURCE_VALUES = {
list: [],
@@ -13,23 +13,20 @@ export function createDatasourcesStore() {
const { subscribe, update, set } = store
async function updateDatasource(response) {
- if (response.status !== 200) {
- throw new Error(await response.text())
- }
-
- const { datasource, error } = await response.json()
+ const { datasource, error } = response
update(state => {
const currentIdx = state.list.findIndex(ds => ds._id === datasource._id)
-
const sources = state.list
-
if (currentIdx >= 0) {
sources.splice(currentIdx, 1, datasource)
} else {
sources.push(datasource)
}
-
- return { list: sources, selected: datasource._id, schemaError: error }
+ return {
+ list: sources,
+ selected: datasource._id,
+ schemaError: error,
+ }
})
return datasource
}
@@ -38,25 +35,25 @@ export function createDatasourcesStore() {
subscribe,
update,
init: async () => {
- const response = await api.get(`/api/datasources`)
- const json = await response.json()
- set({ list: json, selected: null })
+ const datasources = await API.getDatasources()
+ set({
+ list: datasources,
+ selected: null,
+ })
},
fetch: async () => {
- const response = await api.get(`/api/datasources`)
- const json = await response.json()
+ const datasources = await API.getDatasources()
// Clear selected if it no longer exists, otherwise keep it
const selected = get(store).selected
let nextSelected = null
- if (selected && json.find(source => source._id === selected)) {
+ if (selected && datasources.find(source => source._id === selected)) {
nextSelected = selected
}
- update(state => ({ ...state, list: json, selected: nextSelected }))
- return json
+ update(state => ({ ...state, list: datasources, selected: nextSelected }))
},
- select: async datasourceId => {
+ select: datasourceId => {
update(state => ({ ...state, selected: datasourceId }))
queries.unselect()
tables.unselect()
@@ -66,37 +63,33 @@ export function createDatasourcesStore() {
update(state => ({ ...state, selected: null }))
},
updateSchema: async datasource => {
- let url = `/api/datasources/${datasource._id}/schema`
-
- const response = await api.post(url)
- return updateDatasource(response)
+ const response = await API.buildDatasourceSchema(datasource?._id)
+ return await updateDatasource(response)
},
save: async (body, fetchSchema = false) => {
let response
if (body._id) {
- response = await api.put(`/api/datasources/${body._id}`, body)
+ response = await API.updateDatasource(body)
} else {
- response = await api.post("/api/datasources", {
+ response = await API.createDatasource({
datasource: body,
fetchSchema,
})
}
-
return updateDatasource(response)
},
delete: async datasource => {
- const response = await api.delete(
- `/api/datasources/${datasource._id}/${datasource._rev}`
- )
+ await API.deleteDatasource({
+ datasourceId: datasource?._id,
+ datasourceRev: datasource?._rev,
+ })
update(state => {
const sources = state.list.filter(
existing => existing._id !== datasource._id
)
return { list: sources, selected: null }
})
-
await queries.fetch()
- return response
},
removeSchemaError: () => {
update(state => {
diff --git a/packages/builder/src/stores/backend/flags.js b/packages/builder/src/stores/backend/flags.js
index 7e5adcd00f..449d010640 100644
--- a/packages/builder/src/stores/backend/flags.js
+++ b/packages/builder/src/stores/backend/flags.js
@@ -1,37 +1,27 @@
import { writable } from "svelte/store"
-import api from "builderStore/api"
+import { API } from "api"
export function createFlagsStore() {
const { subscribe, set } = writable({})
- return {
- subscribe,
+ const actions = {
fetch: async () => {
- const { doc, response } = await getFlags()
- set(doc)
- return response
+ const flags = await API.getFlags()
+ set(flags)
},
updateFlag: async (flag, value) => {
- const response = await api.post("/api/users/flags", {
+ await API.updateFlag({
flag,
value,
})
- if (response.status === 200) {
- const { doc } = await getFlags()
- set(doc)
- }
- return response
+ await actions.fetch()
},
}
-}
-async function getFlags() {
- const response = await api.get("/api/users/flags")
- let doc = {}
- if (response.status === 200) {
- doc = await response.json()
+ return {
+ subscribe,
+ ...actions,
}
- return { doc, response }
}
export const flags = createFlagsStore()
diff --git a/packages/builder/src/stores/backend/integrations.js b/packages/builder/src/stores/backend/integrations.js
index c19b09f1fb..717b656c72 100644
--- a/packages/builder/src/stores/backend/integrations.js
+++ b/packages/builder/src/stores/backend/integrations.js
@@ -7,12 +7,8 @@ const createIntegrationsStore = () => {
return {
...store,
init: async () => {
- try {
- const integrations = await API.getIntegrations()
- store.set(integrations)
- } catch (error) {
- store.set(null)
- }
+ const integrations = await API.getIntegrations()
+ store.set(integrations)
},
}
}
diff --git a/packages/builder/src/stores/backend/permissions.js b/packages/builder/src/stores/backend/permissions.js
index 29159494ed..aaab406bc9 100644
--- a/packages/builder/src/stores/backend/permissions.js
+++ b/packages/builder/src/stores/backend/permissions.js
@@ -1,5 +1,5 @@
import { writable } from "svelte/store"
-import api from "builderStore/api"
+import { API } from "api"
export function createPermissionStore() {
const { subscribe } = writable([])
@@ -7,14 +7,14 @@ export function createPermissionStore() {
return {
subscribe,
save: async ({ level, role, resource }) => {
- const response = await api.post(
- `/api/permission/${role}/${resource}/${level}`
- )
- return await response.json()
+ return await API.updatePermissionForResource({
+ resourceId: resource,
+ roleId: role,
+ level,
+ })
},
forResource: async resourceId => {
- const response = await api.get(`/api/permission/${resourceId}`)
- return await response.json()
+ return await API.getPermissionForResource(resourceId)
},
}
}
diff --git a/packages/builder/src/stores/backend/queries.js b/packages/builder/src/stores/backend/queries.js
index 2018933ffc..6e30cb21f8 100644
--- a/packages/builder/src/stores/backend/queries.js
+++ b/packages/builder/src/stores/backend/queries.js
@@ -1,6 +1,6 @@
import { writable, get } from "svelte/store"
import { datasources, integrations, tables, views } from "./"
-import api from "builderStore/api"
+import { API } from "api"
import { duplicateName } from "../../helpers/duplicate"
const sortQueries = queryList => {
@@ -15,23 +15,26 @@ export function createQueriesStore() {
const actions = {
init: async () => {
- const response = await api.get(`/api/queries`)
- const json = await response.json()
- set({ list: json, selected: null })
+ const queries = await API.getQueries()
+ set({
+ list: queries,
+ selected: null,
+ })
},
fetch: async () => {
- const response = await api.get(`/api/queries`)
- const json = await response.json()
- sortQueries(json)
- update(state => ({ ...state, list: json }))
- return json
+ const queries = await API.getQueries()
+ sortQueries(queries)
+ update(state => ({
+ ...state,
+ list: queries,
+ }))
},
save: async (datasourceId, query) => {
const _integrations = get(integrations)
const dataSource = get(datasources).list.filter(
ds => ds._id === datasourceId
)
- // check if readable attribute is found
+ // Check if readable attribute is found
if (dataSource.length !== 0) {
const integration = _integrations[dataSource[0].source]
const readable = integration.query[query.queryVerb].readable
@@ -40,34 +43,28 @@ export function createQueriesStore() {
}
}
query.datasourceId = datasourceId
- const response = await api.post(`/api/queries`, query)
- if (response.status !== 200) {
- throw new Error("Failed saving query.")
- }
- const json = await response.json()
+ const savedQuery = await API.saveQuery(query)
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
-
- if (currentIdx >= 0) {
- queries.splice(currentIdx, 1, json)
+ if (idx >= 0) {
+ queries.splice(idx, 1, savedQuery)
} else {
- queries.push(json)
+ queries.push(savedQuery)
}
sortQueries(queries)
- return { list: queries, selected: json._id }
+ return {
+ list: queries,
+ selected: savedQuery._id,
+ }
})
- return json
+ return savedQuery
},
- import: async body => {
- const response = await api.post(`/api/queries/import`, body)
-
- if (response.status !== 200) {
- throw new Error(response.message)
- }
-
- return response.json()
+ import: async (data, datasourceId) => {
+ return await API.importQueries({
+ datasourceId,
+ data,
+ })
},
select: query => {
update(state => ({ ...state, selected: query._id }))
@@ -79,48 +76,37 @@ export function createQueriesStore() {
update(state => ({ ...state, selected: null }))
},
preview: async query => {
- const response = await api.post("/api/queries/preview", {
- fields: query.fields,
- queryVerb: query.queryVerb,
- transformer: query.transformer,
- parameters: query.parameters.reduce(
- (acc, next) => ({
- ...acc,
- [next.name]: next.default,
- }),
- {}
- ),
- datasourceId: query.datasourceId,
- queryId: query._id || undefined,
+ const parameters = query.parameters.reduce(
+ (acc, next) => ({
+ ...acc,
+ [next.name]: next.default,
+ }),
+ {}
+ )
+ const result = await API.previewQuery({
+ ...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
// unique fields returned by the server
const schema = {}
- for (let field of json.schemaFields) {
+ for (let field of result.schemaFields) {
schema[field] = "string"
}
- return { ...json, schema, rows: json.rows || [] }
+ return { ...result, schema, rows: result.rows || [] }
},
delete: async query => {
- const response = await api.delete(
- `/api/queries/${query._id}/${query._rev}`
- )
+ await API.deleteQuery({
+ queryId: query?._id,
+ queryRev: query?._rev,
+ })
update(state => {
state.list = state.list.filter(existing => existing._id !== query._id)
if (state.selected === query._id) {
state.selected = null
}
-
return state
})
- return response
},
duplicate: async query => {
let list = get(store).list
diff --git a/packages/builder/src/stores/backend/roles.js b/packages/builder/src/stores/backend/roles.js
index 1a1a9c04c5..0c3cdbce5a 100644
--- a/packages/builder/src/stores/backend/roles.js
+++ b/packages/builder/src/stores/backend/roles.js
@@ -1,30 +1,32 @@
import { writable } from "svelte/store"
-import api from "builderStore/api"
+import { API } from "api"
export function createRolesStore() {
const { subscribe, update, set } = writable([])
- return {
- subscribe,
+ const actions = {
fetch: async () => {
- set(await getRoles())
+ const roles = await API.getRoles()
+ set(roles)
},
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))
- return response
},
save: async role => {
- const response = await api.post("/api/roles", role)
- set(await getRoles())
- return response
+ const savedRole = await API.saveRole(role)
+ await actions.fetch()
+ return savedRole
},
}
+
+ return {
+ subscribe,
+ ...actions,
+ }
}
-async function getRoles() {
- const response = await api.get("/api/roles")
- return await response.json()
-}
-
export const roles = createRolesStore()
diff --git a/packages/builder/src/stores/backend/tables.js b/packages/builder/src/stores/backend/tables.js
index 02db48c549..f6d20037cb 100644
--- a/packages/builder/src/stores/backend/tables.js
+++ b/packages/builder/src/stores/backend/tables.js
@@ -1,7 +1,7 @@
import { get, writable } from "svelte/store"
import { datasources, queries, views } from "./"
import { cloneDeep } from "lodash/fp"
-import api from "builderStore/api"
+import { API } from "api"
import { SWITCHABLE_TYPES } from "../../constants/backend"
export function createTablesStore() {
@@ -9,10 +9,11 @@ export function createTablesStore() {
const { subscribe, update, set } = store
async function fetch() {
- const tablesResponse = await api.get(`/api/tables`)
- const tables = await tablesResponse.json()
- update(state => ({ ...state, list: tables }))
- return tables
+ const tables = await API.getTables()
+ update(state => ({
+ ...state,
+ list: tables,
+ }))
}
async function select(table) {
@@ -38,16 +39,16 @@ export function createTablesStore() {
const oldTable = get(store).list.filter(t => t._id === table._id)[0]
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)) {
- // if field name has been seen before remove it
+ // If field name has been seen before remove it
if (fieldNames.indexOf(key.toLowerCase()) !== -1) {
delete updatedTable.schema[key]
continue
}
const field = updatedTable.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 (
oldField != null &&
oldField?.type !== field.type &&
@@ -55,21 +56,17 @@ export function createTablesStore() {
) {
updatedTable.schema[key] = oldField
}
- // field has been renamed
+ // Field has been renamed
if (field.name && field.name !== key) {
updatedTable.schema[field.name] = field
updatedTable._rename = { old: key, updated: field.name }
delete updatedTable.schema[key]
}
- // finally record this field has been used
+ // Finally record this field has been used
fieldNames.push(key.toLowerCase())
}
- const response = await api.post(`/api/tables`, updatedTable)
- if (response.status !== 200) {
- throw (await response.json()).message
- }
- const savedTable = await response.json()
+ const savedTable = await API.saveTable(updatedTable)
await fetch()
if (table.type === "external") {
await datasources.fetch()
@@ -91,21 +88,18 @@ export function createTablesStore() {
},
save,
init: async () => {
- const response = await api.get("/api/tables")
- const json = await response.json()
+ const tables = await API.getTables()
set({
- list: json,
+ list: tables,
selected: {},
draft: {},
})
},
delete: async table => {
- const response = await api.delete(
- `/api/tables/${table._id}/${table._rev}`
- )
- if (response.status !== 200) {
- throw (await response.json()).message
- }
+ await API.deleteTable({
+ tableId: table?._id,
+ tableRev: table?._rev,
+ })
update(state => ({
...state,
list: state.list.filter(existing => existing._id !== table._id),
@@ -156,12 +150,16 @@ export function createTablesStore() {
await promise
}
},
- deleteField: field => {
+ deleteField: async field => {
+ let promise
update(state => {
delete state.draft.schema[field.name]
- save(state.draft)
+ promise = save(state.draft)
return state
})
+ if (promise) {
+ await promise
+ }
},
}
}
diff --git a/packages/builder/src/stores/backend/views.js b/packages/builder/src/stores/backend/views.js
index 14c7bf92a4..849a66f671 100644
--- a/packages/builder/src/stores/backend/views.js
+++ b/packages/builder/src/stores/backend/views.js
@@ -1,6 +1,6 @@
import { writable, get } from "svelte/store"
import { tables, datasources, queries } from "./"
-import api from "builderStore/api"
+import { API } from "api"
export function createViewsStore() {
const { subscribe, update } = writable({
@@ -11,7 +11,7 @@ export function createViewsStore() {
return {
subscribe,
update,
- select: async view => {
+ select: view => {
update(state => ({
...state,
selected: view,
@@ -27,16 +27,14 @@ export function createViewsStore() {
}))
},
delete: async view => {
- await api.delete(`/api/views/${view}`)
+ await API.deleteView(view)
await tables.fetch()
},
save: async view => {
- const response = await api.post(`/api/views`, view)
- const json = await response.json()
-
+ const savedView = await API.saveView(view)
const viewMeta = {
name: view.name,
- ...json,
+ ...savedView,
}
const viewTable = get(tables).list.find(
diff --git a/packages/builder/src/stores/portal/email.js b/packages/builder/src/stores/portal/email.js
index a015480141..5bef63701f 100644
--- a/packages/builder/src/stores/portal/email.js
+++ b/packages/builder/src/stores/portal/email.js
@@ -1,5 +1,6 @@
import { writable } from "svelte/store"
-import api from "builderStore/api"
+import { API } from "api"
+import { notifications } from "@budibase/bbui"
export function createEmailStore() {
const store = writable({})
@@ -8,34 +9,35 @@ export function createEmailStore() {
subscribe: store.subscribe,
templates: {
fetch: async () => {
- // fetch the email template definitions
- const response = await api.get(`/api/global/template/definitions`)
- const definitions = await response.json()
-
- // fetch the email templates themselves
- const templatesResponse = await api.get(`/api/global/template/email`)
- const templates = await templatesResponse.json()
-
- store.set({
- definitions,
- templates,
- })
+ try {
+ // fetch the email template definitions and templates
+ const definitions = await API.getEmailTemplateDefinitions()
+ const templates = await API.getEmailTemplates()
+ store.set({
+ definitions,
+ templates,
+ })
+ } catch (error) {
+ notifications.error("Error fetching email templates")
+ store.set({})
+ }
},
save: async template => {
- // Save your template config
- const response = await api.post(`/api/global/template`, template)
- const json = await response.json()
- if (response.status !== 200) throw new Error(json.message)
- template._rev = json._rev
- template._id = json._id
-
- store.update(state => {
- const currentIdx = state.templates.findIndex(
- template => template.purpose === json.purpose
- )
- state.templates.splice(currentIdx, 1, template)
- return state
- })
+ try {
+ // Save your template config
+ const savedTemplate = await API.saveEmailTemplate(template)
+ template._rev = savedTemplate._rev
+ template._id = savedTemplate._id
+ store.update(state => {
+ const currentIdx = state.templates.findIndex(
+ template => template.purpose === savedTemplate.purpose
+ )
+ state.templates.splice(currentIdx, 1, template)
+ return state
+ })
+ } catch (error) {
+ notifications.error("Error saving email template")
+ }
},
},
}
diff --git a/packages/frontend-core/src/api/datasources.js b/packages/frontend-core/src/api/datasources.js
new file mode 100644
index 0000000000..ff72fbf25b
--- /dev/null
+++ b/packages/frontend-core/src/api/datasources.js
@@ -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}`,
+ })
+ },
+})
diff --git a/packages/frontend-core/src/api/flags.js b/packages/frontend-core/src/api/flags.js
new file mode 100644
index 0000000000..bb545e83b9
--- /dev/null
+++ b/packages/frontend-core/src/api/flags.js
@@ -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,
+ },
+ })
+ },
+})
diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js
index 91a400a389..9511a946b4 100644
--- a/packages/frontend-core/src/api/index.js
+++ b/packages/frontend-core/src/api/index.js
@@ -4,13 +4,18 @@ import { buildAppEndpoints } from "./app"
import { buildAttachmentEndpoints } from "./attachments"
import { buildAuthEndpoints } from "./auth"
import { buildAutomationEndpoints } from "./automations"
+import { buildDatasourceEndpoints } from "./datasources"
+import { buildFlagEndpoints } from "./flags"
import { buildHostingEndpoints } from "./hosting"
+import { buildPermissionsEndpoints } from "./permissions"
import { buildQueryEndpoints } from "./queries"
import { buildRelationshipEndpoints } from "./relationships"
+import { buildRoleEndpoints } from "./roles"
import { buildRouteEndpoints } from "./routes"
import { buildRowEndpoints } from "./rows"
import { buildScreenEndpoints } from "./screens"
import { buildTableEndpoints } from "./tables"
+import { buildTemplateEndpoints } from "./templates"
import { buildViewEndpoints } from "./views"
const defaultAPIClientConfig = {
@@ -184,13 +189,18 @@ export const createAPIClient = config => {
...buildAttachmentEndpoints(API),
...buildAuthEndpoints(API),
...buildAutomationEndpoints(API),
+ ...buildDatasourceEndpoints(API),
+ ...buildFlagEndpoints(API),
...buildHostingEndpoints(API),
+ ...buildPermissionsEndpoints(API),
...buildQueryEndpoints(API),
...buildRelationshipEndpoints(API),
+ ...buildRoleEndpoints(API),
...buildRouteEndpoints(API),
...buildRowEndpoints(API),
...buildScreenEndpoints(API),
...buildTableEndpoints(API),
+ ...buildTemplateEndpoints(API),
...buildViewEndpoints(API),
}
diff --git a/packages/frontend-core/src/api/permissions.js b/packages/frontend-core/src/api/permissions.js
new file mode 100644
index 0000000000..5407cb3ce5
--- /dev/null
+++ b/packages/frontend-core/src/api/permissions.js
@@ -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}`,
+ })
+ },
+})
diff --git a/packages/frontend-core/src/api/queries.js b/packages/frontend-core/src/api/queries.js
index 6c3ce900f9..f18ec7c4ec 100644
--- a/packages/frontend-core/src/api/queries.js
+++ b/packages/frontend-core/src/api/queries.js
@@ -1,6 +1,9 @@
export const buildQueryEndpoints = API => ({
/**
* 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 }) => {
return await API.post({
@@ -14,6 +17,7 @@ export const buildQueryEndpoints = API => ({
/**
* Fetches the definition of an external query.
+ * @param queryId the ID of thr query to fetch the definition of
*/
fetchQueryDefinition: async queryId => {
return await API.get({
@@ -21,4 +25,61 @@ export const buildQueryEndpoints = API => ({
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,
+ })
+ },
})
diff --git a/packages/frontend-core/src/api/roles.js b/packages/frontend-core/src/api/roles.js
new file mode 100644
index 0000000000..15c27091c4
--- /dev/null
+++ b/packages/frontend-core/src/api/roles.js
@@ -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",
+ })
+ },
+})
diff --git a/packages/frontend-core/src/api/tables.js b/packages/frontend-core/src/api/tables.js
index 0785b2eed3..1f8b450a2a 100644
--- a/packages/frontend-core/src/api/tables.js
+++ b/packages/frontend-core/src/api/tables.js
@@ -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}`,
+ })
+ },
})
diff --git a/packages/frontend-core/src/api/templates.js b/packages/frontend-core/src/api/templates.js
new file mode 100644
index 0000000000..7cd1d78d7b
--- /dev/null
+++ b/packages/frontend-core/src/api/templates.js
@@ -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,
+ },
+ })
+ },
+})
diff --git a/packages/frontend-core/src/api/views.js b/packages/frontend-core/src/api/views.js
index 661268d957..237a66bc13 100644
--- a/packages/frontend-core/src/api/views.js
+++ b/packages/frontend-core/src/api/views.js
@@ -1,6 +1,10 @@
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 }) => {
const params = new URLSearchParams()
@@ -9,7 +13,7 @@ export const buildViewEndpoints = API => ({
params.set("calculation", calculation)
}
if (groupBy) {
- params.set("group", groupBy ? "true" : "false")
+ params.set("group", groupBy)
}
const QUERY_VIEW_URL = field
? `/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}`,
+ })
+ },
})