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