Fetch app definition and routes from the server

This commit is contained in:
Andrew Kingston 2020-11-19 18:39:22 +00:00
parent ef2eba0433
commit 9c30ab2df3
18 changed files with 92 additions and 73 deletions

View File

@ -0,0 +1,10 @@
import API from "./api"
/**
* Fetches screen definition for an app.
*/
export const fetchAppDefinition = async appId => {
return await API.get({
url: `/api/applications/${appId}/definition`,
})
}

View File

@ -1,10 +1,10 @@
import api from "./api" import API from "./api"
/** /**
* Uploads an attachment to the server. * Uploads an attachment to the server.
*/ */
export const uploadAttachment = async data => { export const uploadAttachment = async data => {
return await api.post({ return await API.post({
url: "/api/attachments/upload", url: "/api/attachments/upload",
body: data, body: data,
json: false, json: false,

View File

@ -1,16 +1,16 @@
import api from "./api" import API from "./api"
/** /**
* Performs a log in request. * Performs a log in request.
*/ */
export const logIn = async ({ username, password }) => { export const logIn = async ({ username, password }) => {
if (!username) { if (!username) {
return api.error("Please enter your username") return API.error("Please enter your username")
} }
if (!password) { if (!password) {
return api.error("Please enter your password") return API.error("Please enter your password")
} }
return await api.post({ return await API.post({
url: "/api/authenticate", url: "/api/authenticate",
body: { username, password }, body: { username, password },
}) })

View File

@ -6,3 +6,4 @@ export * from "./attachments"
export * from "./views" export * from "./views"
export * from "./relationships" export * from "./relationships"
export * from "./routes" export * from "./routes"
export * from "./app"

View File

@ -1,4 +1,4 @@
import api from "./api" import API from "./api"
import { enrichRows } from "./rows" import { enrichRows } from "./rows"
/** /**
@ -8,7 +8,7 @@ export const fetchRelationshipData = async ({ tableId, rowId, fieldName }) => {
if (!tableId || !rowId || !fieldName) { if (!tableId || !rowId || !fieldName) {
return [] return []
} }
const response = await api.get({ url: `/api/${tableId}/${rowId}/enrich` }) const response = await API.get({ url: `/api/${tableId}/${rowId}/enrich` })
const rows = response[fieldName] || [] const rows = response[fieldName] || []
return await enrichRows(rows, tableId) return await enrichRows(rows, tableId)
} }

View File

@ -1,10 +1,10 @@
import api from "./api" import API from "./api"
/** /**
* Fetches available routes for the client app. * Fetches available routes for the client app.
*/ */
export const fetchRoutes = async () => { export const fetchRoutes = async () => {
return await api.get({ return await API.get({
url: `/api/routing/client`, url: `/api/routing/client`,
}) })
} }

View File

@ -1,11 +1,11 @@
import api from "./api" import API from "./api"
import { fetchTableDefinition } from "./tables" import { fetchTableDefinition } from "./tables"
/** /**
* Fetches data about a certain row in a table. * Fetches data about a certain row in a table.
*/ */
export const fetchRow = async ({ tableId, rowId }) => { export const fetchRow = async ({ tableId, rowId }) => {
const row = await api.get({ const row = await API.get({
url: `/api/${tableId}/rows/${rowId}`, url: `/api/${tableId}/rows/${rowId}`,
}) })
return (await enrichRows([row], tableId))[0] return (await enrichRows([row], tableId))[0]
@ -15,7 +15,7 @@ export const fetchRow = async ({ tableId, rowId }) => {
* Creates a row in a table. * Creates a row in a table.
*/ */
export const saveRow = async row => { export const saveRow = async row => {
return await api.post({ return await API.post({
url: `/api/${row.tableId}/rows`, url: `/api/${row.tableId}/rows`,
body: row, body: row,
}) })
@ -25,7 +25,7 @@ export const saveRow = async row => {
* Updates a row in a table. * Updates a row in a table.
*/ */
export const updateRow = async row => { export const updateRow = async row => {
return await api.patch({ return await API.patch({
url: `/api/${row.tableId}/rows/${row._id}`, url: `/api/${row.tableId}/rows/${row._id}`,
body: row, body: row,
}) })
@ -35,7 +35,7 @@ export const updateRow = async row => {
* Deletes a row from a table. * Deletes a row from a table.
*/ */
export const deleteRow = async ({ tableId, rowId, revId }) => { export const deleteRow = async ({ tableId, rowId, revId }) => {
return await api.del({ return await API.del({
url: `/api/${tableId}/rows/${rowId}/${revId}`, url: `/api/${tableId}/rows/${rowId}/${revId}`,
}) })
} }
@ -44,7 +44,7 @@ export const deleteRow = async ({ tableId, rowId, revId }) => {
* Deletes many rows from a table. * Deletes many rows from a table.
*/ */
export const deleteRows = async ({ tableId, rows }) => { export const deleteRows = async ({ tableId, rows }) => {
return await api.post({ return await API.post({
url: `/api/${tableId}/rows`, url: `/api/${tableId}/rows`,
body: { body: {
rows, rows,

View File

@ -1,4 +1,4 @@
import api from "./api" import API from "./api"
import { enrichRows } from "./rows" import { enrichRows } from "./rows"
/** /**
@ -6,13 +6,13 @@ import { enrichRows } from "./rows"
* Since definitions cannot change at runtime, the result is cached. * Since definitions cannot change at runtime, the result is cached.
*/ */
export const fetchTableDefinition = async tableId => { export const fetchTableDefinition = async tableId => {
return await api.get({ url: `/api/tables/${tableId}`, cache: true }) return await API.get({ url: `/api/tables/${tableId}`, cache: true })
} }
/** /**
* Fetches all rows from a table. * Fetches all rows from a table.
*/ */
export const fetchTableData = async tableId => { export const fetchTableData = async tableId => {
const rows = await api.get({ url: `/api/${tableId}/rows` }) const rows = await API.get({ url: `/api/${tableId}/rows` })
return await enrichRows(rows, tableId) return await enrichRows(rows, tableId)
} }

View File

@ -1,4 +1,4 @@
import api from "./api" import API from "./api"
import { enrichRows } from "./rows" import { enrichRows } from "./rows"
/** /**
@ -25,6 +25,6 @@ export const fetchViewData = async ({
? `/api/views/${name}?${params}` ? `/api/views/${name}?${params}`
: `/api/views/${name}` : `/api/views/${name}`
const rows = await api.get({ url: QUERY_VIEW_URL }) const rows = await API.get({ url: QUERY_VIEW_URL })
return await enrichRows(rows, tableId) return await enrichRows(rows, tableId)
} }

View File

@ -1,14 +1,22 @@
<script> <script>
import { setContext } from "svelte" import { setContext, onMount } from "svelte"
import Component from "./Component.svelte" import Component from "./Component.svelte"
import SDK from "../sdk" import SDK from "../sdk"
import { routeStore, screenStore } from "../store"
// Provide SDK for components // Provide SDK for components
setContext("app", SDK) setContext("app", SDK)
const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] let loaded = false
$: pageDefinition = frontendDefinition?.page?.props
$: console.log(frontendDefinition) // Load app config
onMount(async () => {
await routeStore.actions.fetchRoutes()
await screenStore.actions.fetchScreens()
loaded = true
})
</script> </script>
<Component definition={pageDefinition} /> {#if loaded}
<Component definition={$screenStore.page.props} />
{/if}

View File

@ -6,27 +6,26 @@
import { styleable } from "../utils" import { styleable } from "../utils"
export let styles export let styles
let routes $: routerConfig = getRouterConfig($routeStore.routes)
onMount(async () => { const getRouterConfig = routes => {
await routeStore.actions.fetchRoutes() let config = {}
await screenStore.actions.fetchScreens() routes.forEach(route => {
routes = {} config[route.path] = Screen
$routeStore.routes.forEach(route => {
routes[route.path] = Screen
}) })
// Add catch-all route so that we serve the Screen component always // Add catch-all route so that we serve the Screen component always
routes["*"] = Screen config["*"] = Screen
}) return config
}
function onRouteLoading({ detail }) { const onRouteLoading = ({ detail }) => {
routeStore.actions.setActiveRoute(detail.route) routeStore.actions.setActiveRoute(detail.route)
} }
</script> </script>
{#if routes} {#if routerConfig}
<div use:styleable={styles}> <div use:styleable={styles}>
<Router on:routeLoading={onRouteLoading} {routes} /> <Router on:routeLoading={onRouteLoading} routes={routerConfig} />
</div> </div>
{/if} {/if}

View File

@ -1,6 +1,7 @@
import * as API from "../api" import * as API from "../api"
import { getAppId } from "../utils" import { getAppId } from "../utils"
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { loc } from "svelte-spa-router"
const createAuthStore = () => { const createAuthStore = () => {
const store = writable("") const store = writable("")
@ -12,8 +13,8 @@ const createAuthStore = () => {
const user = await API.logIn({ username, password }) const user = await API.logIn({ username, password })
if (!user.error) { if (!user.error) {
store.set(user.token) store.set(user.token)
location.reload()
} }
return !user.error
} }
/** /**
@ -21,14 +22,13 @@ const createAuthStore = () => {
*/ */
const logOut = () => { const logOut = () => {
store.set("") store.set("")
// Expire any cookies
const appId = getAppId() const appId = getAppId()
if (appId) { if (appId) {
for (let environment of ["local", "cloud"]) { for (let environment of ["local", "cloud"]) {
window.document.cookie = `budibase:${appId}:${environment}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;` window.document.cookie = `budibase:${appId}:${environment}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;`
} }
} }
location.reload()
} }
return { return {

View File

@ -12,18 +12,15 @@ const createRouteStore = () => {
const fetchRoutes = async () => { const fetchRoutes = async () => {
const routeConfig = await API.fetchRoutes() const routeConfig = await API.fetchRoutes()
let routes = {} let routes = []
Object.values(routeConfig.routes).forEach(pathConfig => { Object.values(routeConfig.routes).forEach(route => {
Object.entries(config).forEach(([subPath, subPathConfig]) => {}) Object.entries(route.subpaths).forEach(([path, config]) => {
routes.push({
path,
screenId: config.screenId,
})
})
}) })
console.log(routes2)
const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"]
const routes = frontendDefinition.screens.map(screen => ({
path: screen.route,
screenId: screen._id,
}))
store.update(state => { store.update(state => {
state.routes = routes state.routes = routes
return state return state

View File

@ -1,22 +1,34 @@
import { writable, derived } from "svelte/store" import { writable, derived } from "svelte/store"
import { routeStore } from "./routes" import { routeStore } from "./routes"
import * as API from "../api"
import { getAppId } from "../utils"
const createScreenStore = () => { const createScreenStore = () => {
const screens = writable([]) const config = writable({
const store = derived([screens, routeStore], ([$screens, $routeStore]) => { screens: [],
page: {},
})
const store = derived([config, routeStore], ([$config, $routeStore]) => {
const { screens, page } = $config
const activeScreen = const activeScreen =
$screens.length === 1 screens.length === 1
? $screens[0] ? screens[0]
: $screens.find(screen => screen.route === $routeStore.activeRoute) : screens.find(
screen => screen.routing.route === $routeStore.activeRoute
)
return { return {
screens: $screens, screens,
page,
activeScreen, activeScreen,
} }
}) })
const fetchScreens = () => { const fetchScreens = async () => {
const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] const appDefinition = await API.fetchAppDefinition(getAppId())
screens.set(frontendDefinition.screens) config.set({
screens: appDefinition.screens,
page: appDefinition.page,
})
} }
return { return {

View File

@ -14,12 +14,10 @@
<style> <style>
div { div {
position: relative; position: relative;
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
} }
div :global(> *) { div :global(> *) {
flex: 1 1 auto; width: 100%;
height: 100%;
position: absolute;
} }
</style> </style>

View File

@ -24,12 +24,7 @@
const login = async () => { const login = async () => {
loading = true loading = true
const success = await authStore.actions.logIn({ username, password }) await authStore.actions.logIn({ username, password })
if (success) {
location.reload()
} else {
error = true
}
loading = false loading = false
} }
</script> </script>

View File

@ -9,7 +9,6 @@
const logOut = () => { const logOut = () => {
authStore.actions.logOut() authStore.actions.logOut()
location.reload()
} }
</script> </script>