Add lots more work on refactoring builder to use core API
This commit is contained in:
parent
f2e45e892c
commit
ca6fa1334a
|
@ -1,95 +1,130 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api from "../../api"
|
import { API } from "api"
|
||||||
import Automation from "./Automation"
|
import Automation from "./Automation"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
|
const initialAutomationState = {
|
||||||
|
automations: [],
|
||||||
|
blockDefinitions: {
|
||||||
|
TRIGGER: [],
|
||||||
|
ACTION: [],
|
||||||
|
},
|
||||||
|
selectedAutomation: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAutomationStore = () => {
|
||||||
|
const store = writable(initialAutomationState)
|
||||||
|
store.actions = automationActions(store)
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|
||||||
const automationActions = store => ({
|
const automationActions = store => ({
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const responses = await Promise.all([
|
try {
|
||||||
api.get(`/api/automations`),
|
const responses = await Promise.all([
|
||||||
api.get(`/api/automations/definitions/list`),
|
API.getAutomations(),
|
||||||
])
|
API.getAutomationDefinitions(),
|
||||||
const jsonResponses = await Promise.all(responses.map(x => x.json()))
|
])
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
let selected = state.selectedAutomation?.automation
|
let selected = state.selectedAutomation?.automation
|
||||||
state.automations = jsonResponses[0]
|
state.automations = responses[0]
|
||||||
state.blockDefinitions = {
|
state.blockDefinitions = {
|
||||||
TRIGGER: jsonResponses[1].trigger,
|
TRIGGER: responses[1].trigger,
|
||||||
ACTION: jsonResponses[1].action,
|
ACTION: responses[1].action,
|
||||||
}
|
}
|
||||||
// if previously selected find the new obj and select it
|
// If previously selected find the new obj and select it
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected = jsonResponses[0].filter(
|
selected = responses[0].filter(
|
||||||
automation => automation._id === selected._id
|
automation => automation._id === selected._id
|
||||||
)
|
)
|
||||||
state.selectedAutomation = new Automation(selected[0])
|
state.selectedAutomation = new Automation(selected[0])
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching automations")
|
||||||
|
store.set(initialAutomationState)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
create: async ({ name }) => {
|
create: async ({ name }) => {
|
||||||
const automation = {
|
try {
|
||||||
name,
|
const automation = {
|
||||||
type: "automation",
|
name,
|
||||||
definition: {
|
type: "automation",
|
||||||
steps: [],
|
definition: {
|
||||||
},
|
steps: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const response = await API.createAutomation(automation)
|
||||||
|
store.update(state => {
|
||||||
|
state.automations = [...state.automations, response.automation]
|
||||||
|
store.actions.select(response.automation)
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error creating automation")
|
||||||
}
|
}
|
||||||
const CREATE_AUTOMATION_URL = `/api/automations`
|
|
||||||
const response = await api.post(CREATE_AUTOMATION_URL, automation)
|
|
||||||
const json = await response.json()
|
|
||||||
store.update(state => {
|
|
||||||
state.automations = [...state.automations, json.automation]
|
|
||||||
store.actions.select(json.automation)
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
save: async automation => {
|
save: async automation => {
|
||||||
const UPDATE_AUTOMATION_URL = `/api/automations`
|
try {
|
||||||
const response = await api.put(UPDATE_AUTOMATION_URL, automation)
|
const response = await API.updateAutomation(automation)
|
||||||
const json = await response.json()
|
store.update(state => {
|
||||||
store.update(state => {
|
const updatedAutomation = response.automation
|
||||||
const newAutomation = json.automation
|
const existingIdx = state.automations.findIndex(
|
||||||
const existingIdx = state.automations.findIndex(
|
existing => existing._id === automation._id
|
||||||
existing => existing._id === automation._id
|
)
|
||||||
)
|
if (existingIdx !== -1) {
|
||||||
if (existingIdx !== -1) {
|
state.automations.splice(existingIdx, 1, updatedAutomation)
|
||||||
state.automations.splice(existingIdx, 1, newAutomation)
|
state.automations = [...state.automations]
|
||||||
state.automations = [...state.automations]
|
store.actions.select(updatedAutomation)
|
||||||
store.actions.select(newAutomation)
|
return state
|
||||||
return state
|
}
|
||||||
}
|
})
|
||||||
})
|
notifications.success("Automation saved successfully")
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error saving automation")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
delete: async automation => {
|
delete: async automation => {
|
||||||
const { _id, _rev } = automation
|
try {
|
||||||
const DELETE_AUTOMATION_URL = `/api/automations/${_id}/${_rev}`
|
await API.deleteAutomation({
|
||||||
await api.delete(DELETE_AUTOMATION_URL)
|
automationId: automation?._id,
|
||||||
|
automationRev: automation?._rev,
|
||||||
store.update(state => {
|
})
|
||||||
const existingIdx = state.automations.findIndex(
|
store.update(state => {
|
||||||
existing => existing._id === _id
|
const existingIdx = state.automations.findIndex(
|
||||||
)
|
existing => existing._id === automation?._id
|
||||||
state.automations.splice(existingIdx, 1)
|
)
|
||||||
state.automations = [...state.automations]
|
state.automations.splice(existingIdx, 1)
|
||||||
state.selectedAutomation = null
|
state.automations = [...state.automations]
|
||||||
state.selectedBlock = null
|
state.selectedAutomation = null
|
||||||
return state
|
state.selectedBlock = null
|
||||||
})
|
return state
|
||||||
},
|
})
|
||||||
trigger: async automation => {
|
notifications.success("Automation deleted successfully")
|
||||||
const { _id } = automation
|
} catch (error) {
|
||||||
return await api.post(`/api/automations/${_id}/trigger`)
|
notifications.error("Error deleting automation")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
test: async (automation, testData) => {
|
test: async (automation, testData) => {
|
||||||
const { _id } = automation
|
try {
|
||||||
const response = await api.post(`/api/automations/${_id}/test`, testData)
|
const result = await API.testAutomation({
|
||||||
const json = await response.json()
|
automationId: automation?._id,
|
||||||
store.update(state => {
|
testData,
|
||||||
state.selectedAutomation.testResults = json
|
})
|
||||||
return state
|
store.update(state => {
|
||||||
})
|
state.selectedAutomation.testResults = result
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error testing automation")
|
||||||
|
store.update(state => {
|
||||||
|
state.selectedAutomation.testResults = null
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
select: automation => {
|
select: automation => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
|
@ -143,17 +178,3 @@ const automationActions = store => ({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getAutomationStore = () => {
|
|
||||||
const INITIAL_AUTOMATION_STATE = {
|
|
||||||
automations: [],
|
|
||||||
blockDefinitions: {
|
|
||||||
TRIGGER: [],
|
|
||||||
ACTION: [],
|
|
||||||
},
|
|
||||||
selectedAutomation: null,
|
|
||||||
}
|
|
||||||
const store = writable(INITIAL_AUTOMATION_STATE)
|
|
||||||
store.actions = automationActions(store)
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import api, { get } from "../api"
|
import { API } from "api"
|
||||||
|
import { notifications } from "@budibase/bbui"
|
||||||
|
|
||||||
const INITIAL_HOSTING_UI_STATE = {
|
const INITIAL_HOSTING_UI_STATE = {
|
||||||
appUrl: "",
|
appUrl: "",
|
||||||
|
@ -12,22 +13,40 @@ export const getHostingStore = () => {
|
||||||
const store = writable({ ...INITIAL_HOSTING_UI_STATE })
|
const store = writable({ ...INITIAL_HOSTING_UI_STATE })
|
||||||
store.actions = {
|
store.actions = {
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
const response = await api.get("/api/hosting/urls")
|
try {
|
||||||
const urls = await response.json()
|
const urls = await API.getHostingURLs()
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.appUrl = urls.app
|
state.appUrl = urls.app
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
} catch (error) {
|
||||||
|
store.update(state => {
|
||||||
|
state.appUrl = ""
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
notifications.error("Error fetching hosting URLs")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
fetchDeployedApps: async () => {
|
fetchDeployedApps: async () => {
|
||||||
let deployments = await (await get("/api/hosting/apps")).json()
|
try {
|
||||||
store.update(state => {
|
const deployments = await API.getDeployedApps()
|
||||||
state.deployedApps = deployments
|
store.update(state => {
|
||||||
state.deployedAppNames = Object.values(deployments).map(app => app.name)
|
state.deployedApps = deployments
|
||||||
state.deployedAppUrls = Object.values(deployments).map(app => app.url)
|
state.deployedAppNames = Object.values(deployments).map(
|
||||||
return state
|
app => app.name
|
||||||
})
|
)
|
||||||
return deployments
|
state.deployedAppUrls = Object.values(deployments).map(app => app.url)
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
store.update(state => {
|
||||||
|
state.deployedApps = {}
|
||||||
|
state.deployedAppNames = []
|
||||||
|
state.deployedAppUrls = []
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
notifications.error("Failed detching deployed apps")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
|
|
|
@ -33,23 +33,6 @@
|
||||||
await automationStore.actions.delete(
|
await automationStore.actions.delete(
|
||||||
$automationStore.selectedAutomation?.automation
|
$automationStore.selectedAutomation?.automation
|
||||||
)
|
)
|
||||||
notifications.success("Automation deleted.")
|
|
||||||
}
|
|
||||||
|
|
||||||
async function testAutomation() {
|
|
||||||
const result = await automationStore.actions.trigger(
|
|
||||||
$automationStore.selectedAutomation.automation
|
|
||||||
)
|
|
||||||
if (result.status === 200) {
|
|
||||||
notifications.success(
|
|
||||||
`Automation ${$automationStore.selectedAutomation.automation.name} triggered successfully.`
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
notifications.error(
|
|
||||||
`Failed to trigger automation ${$automationStore.selectedAutomation.automation.name}.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -85,7 +68,7 @@
|
||||||
animate:flip={{ duration: 500 }}
|
animate:flip={{ duration: 500 }}
|
||||||
in:fly|local={{ x: 500, duration: 1500 }}
|
in:fly|local={{ x: 500, duration: 1500 }}
|
||||||
>
|
>
|
||||||
<FlowItem {testDataModal} {testAutomation} {onSelect} {block} />
|
<FlowItem {testDataModal} {onSelect} {block} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,7 +84,7 @@
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
|
||||||
<Modal bind:this={testDataModal} width="30%">
|
<Modal bind:this={testDataModal} width="30%">
|
||||||
<TestDataModal {testAutomation} />
|
<TestDataModal />
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import api from "builderStore/api"
|
|
||||||
|
|
||||||
export async function createUser(user) {
|
|
||||||
const CREATE_USER_URL = `/api/users/metadata`
|
|
||||||
const response = await api.post(CREATE_USER_URL, user)
|
|
||||||
return await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function saveRow(row, tableId) {
|
|
||||||
const SAVE_ROW_URL = `/api/${tableId}/rows`
|
|
||||||
const response = await api.post(SAVE_ROW_URL, row)
|
|
||||||
|
|
||||||
return await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteRow(row) {
|
|
||||||
const DELETE_ROWS_URL = `/api/${row.tableId}/rows`
|
|
||||||
return api.delete(DELETE_ROWS_URL, {
|
|
||||||
_id: row._id,
|
|
||||||
_rev: row._rev,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchDataForTable(tableId) {
|
|
||||||
const FETCH_ROWS_URL = `/api/${tableId}/rows`
|
|
||||||
|
|
||||||
const response = await api.get(FETCH_ROWS_URL)
|
|
||||||
const json = await response.json()
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
throw new Error(json.message)
|
|
||||||
}
|
|
||||||
return json
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@
|
||||||
import { tables, rows } from "stores/backend"
|
import { tables, rows } from "stores/backend"
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
import RowFieldControl from "../RowFieldControl.svelte"
|
import RowFieldControl from "../RowFieldControl.svelte"
|
||||||
import * as api from "../api"
|
import { API } from "api"
|
||||||
import { ModalContent } from "@budibase/bbui"
|
import { ModalContent } from "@budibase/bbui"
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
||||||
import { FIELDS } from "constants/backend"
|
import { FIELDS } from "constants/backend"
|
||||||
|
@ -22,30 +22,30 @@
|
||||||
$: tableSchema = Object.entries(table?.schema ?? {})
|
$: tableSchema = Object.entries(table?.schema ?? {})
|
||||||
|
|
||||||
async function saveRow() {
|
async function saveRow() {
|
||||||
const rowResponse = await api.saveRow(
|
errors = []
|
||||||
{ ...row, tableId: table._id },
|
try {
|
||||||
table._id
|
await API.saveRow({ ...row, tableId: table._id })
|
||||||
)
|
notifications.success("Row saved successfully")
|
||||||
|
rows.save()
|
||||||
if (rowResponse.errors) {
|
dispatch("updaterows")
|
||||||
errors = Object.entries(rowResponse.errors)
|
} catch (error) {
|
||||||
.map(([key, error]) => ({ dataPath: key, message: error }))
|
if (error.handled) {
|
||||||
.flat()
|
const response = error.json
|
||||||
|
if (response?.errors) {
|
||||||
|
errors = Object.entries(response.errors)
|
||||||
|
.map(([key, error]) => ({ dataPath: key, message: error }))
|
||||||
|
.flat()
|
||||||
|
} else if (error.status === 400 && response?.validationErrors) {
|
||||||
|
errors = Object.keys(response.validationErrors).map(field => ({
|
||||||
|
message: `${field} ${response.validationErrors[field][0]}`,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notifications.error("Failed to save row")
|
||||||
|
}
|
||||||
// Prevent modal closing if there were errors
|
// Prevent modal closing if there were errors
|
||||||
return false
|
return false
|
||||||
} else if (rowResponse.status === 400 && rowResponse.validationErrors) {
|
|
||||||
errors = Object.keys(rowResponse.validationErrors).map(field => ({
|
|
||||||
message: `${field} ${rowResponse.validationErrors[field][0]}`,
|
|
||||||
}))
|
|
||||||
return false
|
|
||||||
} else if (rowResponse.status >= 400) {
|
|
||||||
errors = [{ message: rowResponse.message }]
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.success("Row saved successfully.")
|
|
||||||
rows.save(rowResponse)
|
|
||||||
dispatch("updaterows")
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { roles } from "stores/backend"
|
import { roles } from "stores/backend"
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
import RowFieldControl from "../RowFieldControl.svelte"
|
import RowFieldControl from "../RowFieldControl.svelte"
|
||||||
import * as backendApi from "../api"
|
import { API } from "api"
|
||||||
import { ModalContent, Select } from "@budibase/bbui"
|
import { ModalContent, Select } from "@budibase/bbui"
|
||||||
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
import ErrorsBox from "components/common/ErrorsBox.svelte"
|
||||||
|
|
||||||
|
@ -53,27 +53,31 @@
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowResponse = await backendApi.saveRow(
|
try {
|
||||||
{ ...row, tableId: table._id },
|
await API.saveRow({ ...row, tableId: table._id })
|
||||||
table._id
|
notifications.success("User saved successfully")
|
||||||
)
|
rows.save()
|
||||||
if (rowResponse.errors) {
|
dispatch("updaterows")
|
||||||
if (Array.isArray(rowResponse.errors)) {
|
} catch (error) {
|
||||||
errors = rowResponse.errors.map(error => ({ message: error }))
|
if (error.handled) {
|
||||||
|
const response = error.json
|
||||||
|
if (response?.errors) {
|
||||||
|
if (Array.isArray(response.errors)) {
|
||||||
|
errors = response.errors.map(error => ({ message: error }))
|
||||||
|
} else {
|
||||||
|
errors = Object.entries(response.errors)
|
||||||
|
.map(([key, error]) => ({ dataPath: key, message: error }))
|
||||||
|
.flat()
|
||||||
|
}
|
||||||
|
} else if (error.status === 400) {
|
||||||
|
errors = [{ message: response?.message || "Unknown error" }]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
errors = Object.entries(rowResponse.errors)
|
notifications.error("Error saving user")
|
||||||
.map(([key, error]) => ({ dataPath: key, message: error }))
|
|
||||||
.flat()
|
|
||||||
}
|
}
|
||||||
return false
|
// Prevent closing the modal on errors
|
||||||
} else if (rowResponse.status === 400 || rowResponse.status === 500) {
|
|
||||||
errors = [{ message: rowResponse.message }]
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.success("User saved successfully")
|
|
||||||
rows.save(rowResponse)
|
|
||||||
dispatch("updaterows")
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -6,25 +6,26 @@
|
||||||
import RevertModal from "components/deploy/RevertModal.svelte"
|
import RevertModal from "components/deploy/RevertModal.svelte"
|
||||||
import VersionModal from "components/deploy/VersionModal.svelte"
|
import VersionModal from "components/deploy/VersionModal.svelte"
|
||||||
import NPSFeedbackForm from "components/feedback/NPSFeedbackForm.svelte"
|
import NPSFeedbackForm from "components/feedback/NPSFeedbackForm.svelte"
|
||||||
import { get, post } from "builderStore/api"
|
import { API } from "api"
|
||||||
import { auth, admin } from "stores/portal"
|
import { auth, admin } from "stores/portal"
|
||||||
import { isActive, goto, layout, redirect } from "@roxi/routify"
|
import { isActive, goto, layout, redirect } from "@roxi/routify"
|
||||||
import Logo from "assets/bb-emblem.svg"
|
import Logo from "assets/bb-emblem.svg"
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import UpgradeModal from "../../../../components/upgrade/UpgradeModal.svelte"
|
import UpgradeModal from "components/upgrade/UpgradeModal.svelte"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
// Get Package and set store
|
|
||||||
export let application
|
export let application
|
||||||
|
|
||||||
|
// Get Package and set store
|
||||||
let promise = getPackage()
|
let promise = getPackage()
|
||||||
// sync once when you load the app
|
|
||||||
|
// Sync once when you load the app
|
||||||
let hasSynced = false
|
let hasSynced = false
|
||||||
|
let userShouldPostFeedback = false
|
||||||
$: selected = capitalise(
|
$: selected = capitalise(
|
||||||
$layout.children.find(layout => $isActive(layout.path))?.title ?? "data"
|
$layout.children.find(layout => $isActive(layout.path))?.title ?? "data"
|
||||||
)
|
)
|
||||||
|
|
||||||
let userShouldPostFeedback = false
|
|
||||||
|
|
||||||
function previewApp() {
|
function previewApp() {
|
||||||
if (!$auth?.user?.flags?.feedbackSubmitted) {
|
if (!$auth?.user?.flags?.feedbackSubmitted) {
|
||||||
userShouldPostFeedback = true
|
userShouldPostFeedback = true
|
||||||
|
@ -33,34 +34,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPackage() {
|
async function getPackage() {
|
||||||
const res = await get(`/api/applications/${application}/appPackage`)
|
try {
|
||||||
const pkg = await res.json()
|
const pkg = await API.fetchAppPackage(application)
|
||||||
|
await store.actions.initialise(pkg)
|
||||||
if (res.ok) {
|
|
||||||
try {
|
|
||||||
await store.actions.initialise(pkg)
|
|
||||||
// edge case, lock wasn't known to client when it re-directed, or user went directly
|
|
||||||
} catch (err) {
|
|
||||||
if (!err.ok && err.reason === "locked") {
|
|
||||||
$redirect("../../")
|
|
||||||
} else {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await automationStore.actions.fetch()
|
await automationStore.actions.fetch()
|
||||||
await roles.fetch()
|
await roles.fetch()
|
||||||
await flags.fetch()
|
await flags.fetch()
|
||||||
return pkg
|
return pkg
|
||||||
} else {
|
} catch (error) {
|
||||||
throw new Error(pkg)
|
// TODO: some stuff about redirecting if locked
|
||||||
|
// $redirect("../../")
|
||||||
|
notifications.error("Error initialising app")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles navigation between frontend, backend, automation.
|
// Handles navigation between frontend, backend, automation.
|
||||||
// this remembers your last place on each of the sections
|
// This remembers your last place on each of the sections
|
||||||
// e.g. if one of your screens is selected on front end, then
|
// e.g. if one of your screens is selected on front end, then
|
||||||
// you browse to backend, when you click frontend, you will be
|
// you browse to backend, when you click frontend, you will be
|
||||||
// brought back to the same screen
|
// brought back to the same screen.
|
||||||
const topItemNavigate = path => () => {
|
const topItemNavigate = path => () => {
|
||||||
const activeTopNav = $layout.children.find(c => $isActive(c.path))
|
const activeTopNav = $layout.children.find(c => $isActive(c.path))
|
||||||
if (!activeTopNav) return
|
if (!activeTopNav) return
|
||||||
|
@ -74,8 +66,9 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (!hasSynced && application) {
|
if (!hasSynced && application) {
|
||||||
const res = await post(`/api/applications/${application}/sync`)
|
try {
|
||||||
if (res.status !== 200) {
|
await API.syncApp(application)
|
||||||
|
} catch (error) {
|
||||||
notifications.error("Failed to sync with production database")
|
notifications.error("Failed to sync with production database")
|
||||||
}
|
}
|
||||||
hasSynced = true
|
hasSynced = true
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
Toggle,
|
Toggle,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
import { organisation, admin } from "stores/portal"
|
import { organisation, admin } from "stores/portal"
|
||||||
import { Helpers } from "@budibase/bbui"
|
import { Helpers } from "@budibase/bbui"
|
||||||
import analytics, { Events } from "analytics"
|
import analytics, { Events } from "analytics"
|
||||||
|
@ -137,17 +137,6 @@
|
||||||
providers.oidc?.config?.configs[0].clientID &&
|
providers.oidc?.config?.configs[0].clientID &&
|
||||||
providers.oidc?.config?.configs[0].clientSecret
|
providers.oidc?.config?.configs[0].clientSecret
|
||||||
|
|
||||||
async function uploadLogo(file) {
|
|
||||||
let data = new FormData()
|
|
||||||
data.append("file", file)
|
|
||||||
const res = await api.post(
|
|
||||||
`/api/global/configs/upload/logos_oidc/${file.name}`,
|
|
||||||
data,
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
return await res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFileSelected = e => {
|
const onFileSelected = e => {
|
||||||
let fileName = e.target.files[0].name
|
let fileName = e.target.files[0].name
|
||||||
image = e.target.files[0]
|
image = e.target.files[0]
|
||||||
|
@ -156,17 +145,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save(docs) {
|
async function save(docs) {
|
||||||
// only if the user has provided an image, upload it.
|
|
||||||
image && uploadLogo(image)
|
|
||||||
let calls = []
|
let calls = []
|
||||||
|
|
||||||
|
// Only if the user has provided an image, upload it
|
||||||
|
if (image) {
|
||||||
|
let data = new FormData()
|
||||||
|
data.append("file", image)
|
||||||
|
calls.push(
|
||||||
|
API.uploadOIDCLogo({
|
||||||
|
name: image.name,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
docs.forEach(element => {
|
docs.forEach(element => {
|
||||||
if (element.type === ConfigTypes.OIDC) {
|
if (element.type === ConfigTypes.OIDC) {
|
||||||
//Add a UUID here so each config is distinguishable when it arrives at the login page
|
// Add a UUID here so each config is distinguishable when it arrives at the login page
|
||||||
for (let config of element.config.configs) {
|
for (let config of element.config.configs) {
|
||||||
if (!config.uuid) {
|
if (!config.uuid) {
|
||||||
config.uuid = Helpers.uuid()
|
config.uuid = Helpers.uuid()
|
||||||
}
|
}
|
||||||
// callback urls shouldn't be included
|
// Callback urls shouldn't be included
|
||||||
delete config.callbackURL
|
delete config.callbackURL
|
||||||
}
|
}
|
||||||
if (partialOidc) {
|
if (partialOidc) {
|
||||||
|
@ -175,8 +175,8 @@
|
||||||
`Please fill in all required ${ConfigTypes.OIDC} fields`
|
`Please fill in all required ${ConfigTypes.OIDC} fields`
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
calls.push(api.post(`/api/global/configs`, element))
|
calls.push(API.saveConfig(element))
|
||||||
// turn the save button grey when clicked
|
// Turn the save button grey when clicked
|
||||||
oidcSaveButtonDisabled = true
|
oidcSaveButtonDisabled = true
|
||||||
originalOidcDoc = cloneDeep(providers.oidc)
|
originalOidcDoc = cloneDeep(providers.oidc)
|
||||||
}
|
}
|
||||||
|
@ -189,71 +189,70 @@
|
||||||
`Please fill in all required ${ConfigTypes.Google} fields`
|
`Please fill in all required ${ConfigTypes.Google} fields`
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
calls.push(api.post(`/api/global/configs`, element))
|
calls.push(API.saveConfig(element))
|
||||||
googleSaveButtonDisabled = true
|
googleSaveButtonDisabled = true
|
||||||
originalGoogleDoc = cloneDeep(providers.google)
|
originalGoogleDoc = cloneDeep(providers.google)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
calls.length &&
|
|
||||||
|
if (calls.length) {
|
||||||
Promise.all(calls)
|
Promise.all(calls)
|
||||||
.then(responses => {
|
|
||||||
return Promise.all(
|
|
||||||
responses.map(response => {
|
|
||||||
return response.json()
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.then(data => {
|
.then(data => {
|
||||||
data.forEach(res => {
|
data.forEach(res => {
|
||||||
providers[res.type]._rev = res._rev
|
providers[res.type]._rev = res._rev
|
||||||
providers[res.type]._id = res._id
|
providers[res.type]._id = res._id
|
||||||
})
|
})
|
||||||
notifications.success(`Settings saved.`)
|
notifications.success(`Settings saved`)
|
||||||
analytics.captureEvent(Events.SSO.SAVED)
|
analytics.captureEvent(Events.SSO.SAVED)
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(error => {
|
||||||
notifications.error(`Failed to update auth settings. ${err}`)
|
notifications.error(`Failed to update auth settings`)
|
||||||
throw new Error(err.message)
|
console.error(error.message)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await organisation.init()
|
await organisation.init()
|
||||||
// fetch the configs for oauth
|
|
||||||
const googleResponse = await api.get(
|
|
||||||
`/api/global/configs/${ConfigTypes.Google}`
|
|
||||||
)
|
|
||||||
const googleDoc = await googleResponse.json()
|
|
||||||
|
|
||||||
if (!googleDoc._id) {
|
// Fetch Google config
|
||||||
|
let googleDoc
|
||||||
|
try {
|
||||||
|
googleDoc = await API.getConfig(ConfigTypes.Google)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching Google OAuth config")
|
||||||
|
}
|
||||||
|
if (!googleDoc?._id) {
|
||||||
providers.google = {
|
providers.google = {
|
||||||
type: ConfigTypes.Google,
|
type: ConfigTypes.Google,
|
||||||
config: { activated: true },
|
config: { activated: true },
|
||||||
}
|
}
|
||||||
originalGoogleDoc = cloneDeep(googleDoc)
|
originalGoogleDoc = cloneDeep(googleDoc)
|
||||||
} else {
|
} else {
|
||||||
// default activated to true for older configs
|
// Default activated to true for older configs
|
||||||
if (googleDoc.config.activated === undefined) {
|
if (googleDoc.config.activated === undefined) {
|
||||||
googleDoc.config.activated = true
|
googleDoc.config.activated = true
|
||||||
}
|
}
|
||||||
originalGoogleDoc = cloneDeep(googleDoc)
|
originalGoogleDoc = cloneDeep(googleDoc)
|
||||||
providers.google = googleDoc
|
providers.google = googleDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
googleCallbackUrl = providers?.google?.config?.callbackURL
|
googleCallbackUrl = providers?.google?.config?.callbackURL
|
||||||
|
|
||||||
//Get the list of user uploaded logos and push it to the dropdown options.
|
// Get the list of user uploaded logos and push it to the dropdown options.
|
||||||
//This needs to be done before the config call so they're available when the dropdown renders
|
// This needs to be done before the config call so they're available when
|
||||||
const res = await api.get(`/api/global/configs/logos_oidc`)
|
// the dropdown renders.
|
||||||
const configSettings = await res.json()
|
let oidcLogos
|
||||||
|
try {
|
||||||
if (configSettings.config) {
|
oidcLogos = await API.getOIDCLogos()
|
||||||
const logoKeys = Object.keys(configSettings.config)
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching OIDC logos")
|
||||||
|
}
|
||||||
|
if (oidcLogos?.config) {
|
||||||
|
const logoKeys = Object.keys(oidcLogos.config)
|
||||||
logoKeys.map(logoKey => {
|
logoKeys.map(logoKey => {
|
||||||
const logoUrl = configSettings.config[logoKey]
|
const logoUrl = oidcLogos.config[logoKey]
|
||||||
iconDropdownOptions.unshift({
|
iconDropdownOptions.unshift({
|
||||||
label: logoKey,
|
label: logoKey,
|
||||||
value: logoKey,
|
value: logoKey,
|
||||||
|
@ -261,11 +260,15 @@
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const oidcResponse = await api.get(
|
|
||||||
`/api/global/configs/${ConfigTypes.OIDC}`
|
// Fetch OIDC config
|
||||||
)
|
let oidcDoc
|
||||||
const oidcDoc = await oidcResponse.json()
|
try {
|
||||||
if (!oidcDoc._id) {
|
oidcDoc = await API.getConfig(ConfigTypes.OIDC)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error fetching OIDC config")
|
||||||
|
}
|
||||||
|
if (!oidcDoc?._id) {
|
||||||
providers.oidc = {
|
providers.oidc = {
|
||||||
type: ConfigTypes.OIDC,
|
type: ConfigTypes.OIDC,
|
||||||
config: { configs: [{ activated: true }] },
|
config: { configs: [{ activated: true }] },
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { auth, organisation, admin } from "stores/portal"
|
import { auth, organisation, admin } from "stores/portal"
|
||||||
import { post } from "builderStore/api"
|
import { API } from "api"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { redirect } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
@ -32,14 +32,13 @@
|
||||||
let loading = false
|
let loading = false
|
||||||
|
|
||||||
async function uploadLogo(file) {
|
async function uploadLogo(file) {
|
||||||
let data = new FormData()
|
try {
|
||||||
data.append("file", file)
|
let data = new FormData()
|
||||||
const res = await post(
|
data.append("file", file)
|
||||||
"/api/global/configs/upload/settings/logoUrl",
|
await API.uploadLogo(data)
|
||||||
data,
|
} catch (error) {
|
||||||
{}
|
notifications.error("Error uploading logo")
|
||||||
)
|
}
|
||||||
return await res.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveConfig() {
|
async function saveConfig() {
|
||||||
|
@ -55,19 +54,14 @@
|
||||||
company: $values.company ?? "",
|
company: $values.company ?? "",
|
||||||
platformUrl: $values.platformUrl ?? "",
|
platformUrl: $values.platformUrl ?? "",
|
||||||
}
|
}
|
||||||
// remove logo if required
|
|
||||||
|
// Remove logo if required
|
||||||
if (!$values.logo) {
|
if (!$values.logo) {
|
||||||
config.logoUrl = ""
|
config.logoUrl = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update settings
|
// Update settings
|
||||||
const res = await organisation.save(config)
|
await organisation.save(config)
|
||||||
if (res.status === 200) {
|
|
||||||
notifications.success("Settings saved successfully")
|
|
||||||
} else {
|
|
||||||
notifications.error(res.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
notifications,
|
notifications,
|
||||||
Label,
|
Label,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import api from "builderStore/api"
|
import { API } from "api"
|
||||||
import { auth, admin } from "stores/portal"
|
import { auth, admin } from "stores/portal"
|
||||||
import { redirect } from "@roxi/routify"
|
import { redirect } from "@roxi/routify"
|
||||||
|
|
||||||
|
@ -38,8 +38,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVersion() {
|
async function getVersion() {
|
||||||
const response = await api.get("/api/dev/version")
|
try {
|
||||||
version = await response.text()
|
version = await API.getBudibaseVersion()
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error("Error getting Budibase version")
|
||||||
|
version = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|
|
@ -122,4 +122,14 @@ export const buildAppEndpoints = API => ({
|
||||||
url: `/api/dev/${appId}/lock`,
|
url: `/api/dev/${appId}/lock`,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs an app with the production database.
|
||||||
|
* @param appId the ID of the app to sync
|
||||||
|
*/
|
||||||
|
syncApp: async appId => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/applications/${appId}/sync`,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,6 +36,17 @@ export const buildAuthEndpoints = API => ({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a user for an app.
|
||||||
|
* @param user the user to create
|
||||||
|
*/
|
||||||
|
createAppUser: async user => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/users/metadata",
|
||||||
|
body: user,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the current user metadata.
|
* Updates the current user metadata.
|
||||||
* @param metadata the metadata to save
|
* @param metadata the metadata to save
|
||||||
|
@ -116,4 +127,38 @@ export const buildAuthEndpoints = API => ({
|
||||||
url: "/api/system/environment",
|
url: "/api/system/environment",
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the company logo for the environment.
|
||||||
|
* @param data the logo form data
|
||||||
|
*/
|
||||||
|
uploadLogo: async data => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/global/configs/upload/settings/logoUrl",
|
||||||
|
body: data,
|
||||||
|
json: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads a logo for an OIDC provider.
|
||||||
|
* @param name the name of the OIDC provider
|
||||||
|
* @param data the logo form data to upload
|
||||||
|
*/
|
||||||
|
uploadOIDCLogo: async ({ name, data }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/global/configs/upload/logos_oidc/${name}`,
|
||||||
|
body: data,
|
||||||
|
json: false,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of OIDC logos.
|
||||||
|
*/
|
||||||
|
getOIDCLogos: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/global/configs/logos_oidc",
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,4 +8,67 @@ export const buildAutomationEndpoints = API => ({
|
||||||
body: { fields },
|
body: { fields },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests an automation with data.
|
||||||
|
* @param automationId the ID of the automation to test
|
||||||
|
* @param testData the test data to run against the automation
|
||||||
|
*/
|
||||||
|
testAutomation: async ({ automationId, testData }) => {
|
||||||
|
return await API.post({
|
||||||
|
url: `/api/automations/${automationId}/test`,
|
||||||
|
body: testData,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all automations.
|
||||||
|
*/
|
||||||
|
getAutomations: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/automations",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all the definitions for blocks in automations.
|
||||||
|
*/
|
||||||
|
getAutomationDefinitions: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/automations/definitions/list",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an automation.
|
||||||
|
* @param automation the automation to create
|
||||||
|
*/
|
||||||
|
createAutomation: async automation => {
|
||||||
|
return await API.post({
|
||||||
|
url: "/api/automations",
|
||||||
|
body: automation,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an automation.
|
||||||
|
* @param automation the automation to update
|
||||||
|
*/
|
||||||
|
updateAutomation: async automation => {
|
||||||
|
return await API.put({
|
||||||
|
url: "/api/automations",
|
||||||
|
body: automation,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an automation
|
||||||
|
* @param automationId the ID of the automation to delete
|
||||||
|
* @param automationRev the rev of the automation to delete
|
||||||
|
*/
|
||||||
|
deleteAutomation: async ({ automationId, automationRev }) => {
|
||||||
|
return await API.delete({
|
||||||
|
url: `/api/automations/${automationId}/${automationRev}`,
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,13 +5,26 @@ export const buildBuilderEndpoints = API => ({
|
||||||
* @param {string} appId - ID of the currently running app
|
* @param {string} appId - ID of the currently running app
|
||||||
*/
|
*/
|
||||||
fetchComponentLibDefinitions: async appId => {
|
fetchComponentLibDefinitions: async appId => {
|
||||||
return await API.get({ url: `/api/${appId}/components/definitions` })
|
return await API.get({
|
||||||
|
url: `/api/${appId}/components/definitions`,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of available integrations.
|
* Gets the list of available integrations.
|
||||||
*/
|
*/
|
||||||
getIntegrations: async () => {
|
getIntegrations: async () => {
|
||||||
return await API.get({ url: "/api/integrations" })
|
return await API.get({
|
||||||
|
url: "/api/integrations",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the version of the installed Budibase environment.
|
||||||
|
*/
|
||||||
|
getBudibaseVersion: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/dev/version",
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
export const buildHostingEndpoints = API => ({
|
||||||
|
/**
|
||||||
|
* Gets the hosting URLs of the environment.
|
||||||
|
*/
|
||||||
|
getHostingURLs: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/hosting/urls",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of deployed apps.
|
||||||
|
*/
|
||||||
|
getDeployedApps: async () => {
|
||||||
|
return await API.get({
|
||||||
|
url: "/api/hosting/apps",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
|
@ -4,6 +4,7 @@ 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 { buildHostingEndpoints } from "./hosting"
|
||||||
import { buildQueryEndpoints } from "./queries"
|
import { buildQueryEndpoints } from "./queries"
|
||||||
import { buildRelationshipEndpoints } from "./relationships"
|
import { buildRelationshipEndpoints } from "./relationships"
|
||||||
import { buildRouteEndpoints } from "./routes"
|
import { buildRouteEndpoints } from "./routes"
|
||||||
|
@ -35,6 +36,7 @@ export const createAPIClient = config => {
|
||||||
|
|
||||||
// Try to read a message from the error
|
// Try to read a message from the error
|
||||||
let message = response.statusText
|
let message = response.statusText
|
||||||
|
let json = null
|
||||||
try {
|
try {
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
if (json?.message) {
|
if (json?.message) {
|
||||||
|
@ -47,6 +49,7 @@ export const createAPIClient = config => {
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
message,
|
message,
|
||||||
|
json,
|
||||||
status: response.status,
|
status: response.status,
|
||||||
url: response.url,
|
url: response.url,
|
||||||
method,
|
method,
|
||||||
|
@ -58,6 +61,7 @@ export const createAPIClient = config => {
|
||||||
const makeError = message => {
|
const makeError = message => {
|
||||||
return {
|
return {
|
||||||
message,
|
message,
|
||||||
|
json: null,
|
||||||
status: 400,
|
status: 400,
|
||||||
url: "",
|
url: "",
|
||||||
method: "",
|
method: "",
|
||||||
|
@ -173,6 +177,7 @@ export const createAPIClient = config => {
|
||||||
...buildAttachmentEndpoints(API),
|
...buildAttachmentEndpoints(API),
|
||||||
...buildAuthEndpoints(API),
|
...buildAuthEndpoints(API),
|
||||||
...buildAutomationEndpoints(API),
|
...buildAutomationEndpoints(API),
|
||||||
|
...buildHostingEndpoints(API),
|
||||||
...buildQueryEndpoints(API),
|
...buildQueryEndpoints(API),
|
||||||
...buildRelationshipEndpoints(API),
|
...buildRelationshipEndpoints(API),
|
||||||
...buildRouteEndpoints(API),
|
...buildRouteEndpoints(API),
|
||||||
|
|
Loading…
Reference in New Issue