Merge branch 'master' of github.com:Budibase/budibase into enhanced-app-list
This commit is contained in:
commit
b904bba4c7
|
@ -1,40 +0,0 @@
|
|||
<script>
|
||||
import { Label } from "@budibase/bbui"
|
||||
import { getBindableProperties } from "builderStore/dataBinding"
|
||||
import { currentAsset, store } from "builderStore"
|
||||
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
|
||||
|
||||
export let parameters
|
||||
|
||||
let bindingDrawer
|
||||
$: bindings = getBindableProperties($currentAsset, $store.selectedComponentId)
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Label small>Email</Label>
|
||||
<DrawerBindableInput
|
||||
title="Email"
|
||||
value={parameters.email}
|
||||
on:change={value => (parameters.email = value.detail)}
|
||||
{bindings}
|
||||
/>
|
||||
<Label small>Password</Label>
|
||||
<DrawerBindableInput
|
||||
title="Password"
|
||||
value={parameters.password}
|
||||
on:change={value => (parameters.password = value.detail)}
|
||||
{bindings}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
display: grid;
|
||||
column-gap: var(--spacing-l);
|
||||
row-gap: var(--spacing-s);
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: baseline;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
|
@ -1,14 +0,0 @@
|
|||
<script>
|
||||
import { Body } from "@budibase/bbui"
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
<Body size="S">This action doesn't require any additional settings.</Body>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
|
@ -4,8 +4,6 @@ import DeleteRow from "./DeleteRow.svelte"
|
|||
import ExecuteQuery from "./ExecuteQuery.svelte"
|
||||
import TriggerAutomation from "./TriggerAutomation.svelte"
|
||||
import ValidateForm from "./ValidateForm.svelte"
|
||||
import LogIn from "./LogIn.svelte"
|
||||
import LogOut from "./LogOut.svelte"
|
||||
|
||||
// defines what actions are available, when adding a new one
|
||||
// the component is the setup panel for the action
|
||||
|
@ -37,12 +35,4 @@ export default [
|
|||
name: "Validate Form",
|
||||
component: ValidateForm,
|
||||
},
|
||||
{
|
||||
name: "Log In",
|
||||
component: LogIn,
|
||||
},
|
||||
{
|
||||
name: "Log Out",
|
||||
component: LogOut,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
import { goto, params } from "@roxi/routify"
|
||||
import {
|
||||
notifications,
|
||||
Input,
|
||||
|
@ -22,8 +22,12 @@
|
|||
username,
|
||||
password,
|
||||
})
|
||||
notifications.success("Logged in successfully")
|
||||
$goto("../portal")
|
||||
if ($params["?returnUrl"]) {
|
||||
window.location = decodeURIComponent($params["?returnUrl"])
|
||||
} else {
|
||||
notifications.success("Logged in successfully")
|
||||
$goto("../portal")
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
notifications.error("Invalid credentials")
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
!$isActive("./auth") &&
|
||||
!$isActive("./invite")
|
||||
) {
|
||||
$redirect("./auth/login")
|
||||
const returnUrl = encodeURIComponent(window.location.pathname)
|
||||
$redirect("./auth/login?", { returnUrl })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import { auth } from "stores/portal"
|
||||
import { onMount } from "svelte"
|
||||
import { redirect } from "@roxi/routify"
|
||||
|
||||
// If already authenticated, redirect away from the auth section.
|
||||
// Check this onMount rather than a reactive statement to avoid trumping
|
||||
// the login return URL functionality.
|
||||
onMount(() => {
|
||||
if ($auth.user) {
|
||||
$redirect("../")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if !$auth.user}
|
||||
<slot />
|
||||
{/if}
|
|
@ -36,11 +36,13 @@
|
|||
|
||||
onMount(async () => {
|
||||
// Prevent non-builders from accessing the portal
|
||||
if (!$auth.user?.builder?.global) {
|
||||
$redirect("../")
|
||||
} else {
|
||||
await organisation.init()
|
||||
loaded = true
|
||||
if ($auth.user) {
|
||||
if (!$auth.user?.builder?.global) {
|
||||
$redirect("../")
|
||||
} else {
|
||||
await organisation.init()
|
||||
loaded = true
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
initialise,
|
||||
screenStore,
|
||||
authStore,
|
||||
routeStore,
|
||||
builderStore,
|
||||
} from "../store"
|
||||
import { TableNames, ActionTypes } from "../constants"
|
||||
|
||||
|
@ -18,13 +20,13 @@
|
|||
setContext("component", writable({}))
|
||||
setContext("context", createContextStore())
|
||||
|
||||
let loaded = false
|
||||
let dataLoaded = false
|
||||
|
||||
// Load app config
|
||||
onMount(async () => {
|
||||
await initialise()
|
||||
await authStore.actions.fetchUser()
|
||||
loaded = true
|
||||
dataLoaded = true
|
||||
})
|
||||
|
||||
// Register this as a refreshable datasource so that user changes cause
|
||||
|
@ -36,9 +38,22 @@
|
|||
metadata: { dataSource: { type: "table", tableId: TableNames.USERS } },
|
||||
},
|
||||
]
|
||||
|
||||
// Redirect to home layout if no matching route
|
||||
$: {
|
||||
if (dataLoaded && $routeStore.routerLoaded && !$routeStore.activeRoute) {
|
||||
if ($authStore) {
|
||||
routeStore.actions.navigate("/")
|
||||
} else {
|
||||
const returnUrl = `${window.location.pathname}${window.location.hash}`
|
||||
const encodedUrl = encodeURIComponent(returnUrl)
|
||||
window.location = `/builder/auth/login?returnUrl=${encodedUrl}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if loaded && $screenStore.activeLayout}
|
||||
{#if dataLoaded && $screenStore.activeLayout}
|
||||
<div lang="en" dir="ltr" class="spectrum spectrum--medium spectrum--light">
|
||||
<Provider key="user" data={$authStore} {actions}>
|
||||
<Component definition={$screenStore.activeLayout.props} />
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Router from "svelte-spa-router"
|
||||
import { routeStore } from "../store"
|
||||
import Screen from "./Screen.svelte"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<script>
|
||||
import { fade } from "svelte/transition"
|
||||
import { screenStore, routeStore } from "../store"
|
||||
import Component from "./Component.svelte"
|
||||
import Provider from "./Provider.svelte"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
// Keep route params up to date
|
||||
export let params = {}
|
||||
|
@ -11,8 +11,12 @@
|
|||
// Get the screen definition for the current route
|
||||
$: screenDefinition = $screenStore.activeScreen?.props
|
||||
|
||||
// Redirect to home layout if no matching route
|
||||
$: screenDefinition == null && routeStore.actions.navigate("/")
|
||||
// Mark the router as loaded whenever the screen mounts
|
||||
onMount(() => {
|
||||
if (!$routeStore.routerLoaded) {
|
||||
routeStore.actions.setRouterLoaded()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- Ensure to fully remount when screen changes -->
|
||||
|
|
|
@ -8,6 +8,7 @@ const createRouteStore = () => {
|
|||
routeParams: {},
|
||||
activeRoute: null,
|
||||
routeSessionId: Math.random(),
|
||||
routerLoaded: false,
|
||||
}
|
||||
const store = writable(initialState)
|
||||
|
||||
|
@ -47,10 +48,19 @@ const createRouteStore = () => {
|
|||
})
|
||||
}
|
||||
const navigate = push
|
||||
const setRouterLoaded = () => {
|
||||
store.update(state => ({ ...state, routerLoaded: true }))
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe: store.subscribe,
|
||||
actions: { fetchRoutes, navigate, setRouteParams, setActiveRoute },
|
||||
actions: {
|
||||
fetchRoutes,
|
||||
navigate,
|
||||
setRouteParams,
|
||||
setActiveRoute,
|
||||
setRouterLoaded,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,11 @@ const createScreenStore = () => {
|
|||
activeLayout = $builderStore.layout
|
||||
activeScreen = $builderStore.screen
|
||||
} else {
|
||||
// Otherwise find the correct screen by matching the current route
|
||||
activeLayout = { props: { _component: "screenslot" } }
|
||||
|
||||
// Find the correct screen by matching the current route
|
||||
const { screens, layouts } = $config
|
||||
activeLayout = layouts[0]
|
||||
if (screens.length === 1) {
|
||||
activeScreen = screens[0]
|
||||
} else if ($routeStore.activeRoute) {
|
||||
if ($routeStore.activeRoute) {
|
||||
activeScreen = screens.find(
|
||||
screen => screen._id === $routeStore.activeRoute.screenId
|
||||
)
|
||||
|
|
|
@ -22,10 +22,7 @@ const {
|
|||
} = require("../../db/utils")
|
||||
const { BUILTIN_ROLE_IDS, AccessController } = require("@budibase/auth/roles")
|
||||
const { BASE_LAYOUTS } = require("../../constants/layouts")
|
||||
const {
|
||||
createHomeScreen,
|
||||
createLoginScreen,
|
||||
} = require("../../constants/screens")
|
||||
const { createHomeScreen } = require("../../constants/screens")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { processObject } = require("@budibase/string-templates")
|
||||
const { getAllApps } = require("../../utilities")
|
||||
|
@ -208,7 +205,6 @@ exports.create = async function (ctx) {
|
|||
|
||||
ctx.status = 200
|
||||
ctx.body = newApplication
|
||||
ctx.message = `Application ${ctx.request.body.name} created successfully`
|
||||
}
|
||||
|
||||
exports.update = async function (ctx) {
|
||||
|
@ -229,13 +225,11 @@ exports.update = async function (ctx) {
|
|||
data._rev = response.rev
|
||||
|
||||
ctx.status = 200
|
||||
ctx.message = `Application ${application.name} updated successfully.`
|
||||
ctx.body = response
|
||||
}
|
||||
|
||||
exports.delete = async function (ctx) {
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const app = await db.get(DocumentTypes.APP_METADATA)
|
||||
const result = await db.destroy()
|
||||
/* istanbul ignore next */
|
||||
if (!env.isTest()) {
|
||||
|
@ -243,7 +237,6 @@ exports.delete = async function (ctx) {
|
|||
}
|
||||
|
||||
ctx.status = 200
|
||||
ctx.message = `Application ${app.name} deleted successfully.`
|
||||
ctx.body = result
|
||||
}
|
||||
|
||||
|
@ -260,9 +253,5 @@ const createEmptyAppPackage = async (ctx, app) => {
|
|||
homeScreen._id = generateScreenID()
|
||||
screensAndLayouts.push(homeScreen)
|
||||
|
||||
const loginScreen = createLoginScreen(app)
|
||||
loginScreen._id = generateScreenID()
|
||||
screensAndLayouts.push(loginScreen)
|
||||
|
||||
await db.bulkDocs(screensAndLayouts)
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@ const { InternalTables } = require("../../db/utils")
|
|||
const { getFullUser } = require("../../utilities/users")
|
||||
|
||||
exports.fetchSelf = async ctx => {
|
||||
if (!ctx.user) {
|
||||
ctx.throw(403, "No user logged in")
|
||||
}
|
||||
const appId = ctx.appId
|
||||
const { userId } = ctx.user
|
||||
/* istanbul ignore next */
|
||||
|
|
|
@ -28,7 +28,6 @@ describe("/applications", () => {
|
|||
.set(config.defaultHeaders())
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
expect(res.res.statusMessage).toEqual("Application My App created successfully")
|
||||
expect(res.body._id).toBeDefined()
|
||||
})
|
||||
|
||||
|
@ -74,7 +73,7 @@ describe("/applications", () => {
|
|||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
// should have empty packages
|
||||
expect(res.body.screens.length).toEqual(2)
|
||||
expect(res.body.screens.length).toEqual(1)
|
||||
expect(res.body.layouts.length).toEqual(2)
|
||||
})
|
||||
})
|
||||
|
@ -87,7 +86,7 @@ describe("/applications", () => {
|
|||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
expect(res.body.application).toBeDefined()
|
||||
expect(res.body.screens.length).toEqual(2)
|
||||
expect(res.body.screens.length).toEqual(1)
|
||||
expect(res.body.layouts.length).toEqual(2)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -21,7 +21,7 @@ describe("/screens", () => {
|
|||
.set(config.defaultHeaders())
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(res.body.length).toEqual(3)
|
||||
expect(res.body.length).toEqual(2)
|
||||
expect(res.body.some(s => s._id === screen._id)).toEqual(true)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
||||
const { BASE_LAYOUT_PROP_IDS } = require("./layouts")
|
||||
const { LOGO_URL } = require("../constants")
|
||||
|
||||
exports.createHomeScreen = () => ({
|
||||
description: "",
|
||||
|
@ -49,60 +48,3 @@ exports.createHomeScreen = () => ({
|
|||
},
|
||||
name: "home-screen",
|
||||
})
|
||||
|
||||
exports.createLoginScreen = app => ({
|
||||
description: "",
|
||||
url: "",
|
||||
layoutId: BASE_LAYOUT_PROP_IDS.PUBLIC,
|
||||
props: {
|
||||
_instanceName: "LoginScreenContainer",
|
||||
_id: "5beb4c7b-3c8b-49b2-b8b3-d447dc76dda7",
|
||||
_component: "@budibase/standard-components/container",
|
||||
_styles: {
|
||||
normal: {
|
||||
flex: "1 1 auto",
|
||||
display: "flex",
|
||||
"flex-direction": "column",
|
||||
"justify-content": "center",
|
||||
"align-items": "center",
|
||||
},
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
_transition: "fade",
|
||||
type: "div",
|
||||
_children: [
|
||||
{
|
||||
_id: "781e497e-2e7c-11eb-adc1-0242ac120002",
|
||||
_component: "@budibase/standard-components/login",
|
||||
_styles: {
|
||||
normal: {
|
||||
padding: "64px",
|
||||
background: "rgba(255, 255, 255, 0.4)",
|
||||
"border-radius": "0.5rem",
|
||||
"margin-top": "0px",
|
||||
"box-shadow":
|
||||
"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
|
||||
"font-size": "16px",
|
||||
"font-family": "Inter",
|
||||
flex: "0 1 auto",
|
||||
},
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
logo: LOGO_URL,
|
||||
title: `Log in to ${app.name}`,
|
||||
buttonText: "Log In",
|
||||
_children: [],
|
||||
_instanceName: "Login",
|
||||
},
|
||||
],
|
||||
},
|
||||
routing: {
|
||||
route: "/",
|
||||
roleId: BUILTIN_ROLE_IDS.PUBLIC,
|
||||
},
|
||||
name: "login-screen",
|
||||
})
|
||||
|
|
|
@ -160,7 +160,7 @@ exports.generateUserMetadataID = globalId => {
|
|||
*/
|
||||
exports.getGlobalIDFromUserMetadataID = id => {
|
||||
const prefix = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
|
||||
if (!id.includes(prefix)) {
|
||||
if (!id || !id.includes(prefix)) {
|
||||
return id
|
||||
}
|
||||
return id.split(prefix)[1]
|
||||
|
|
|
@ -18,6 +18,11 @@ const WEBHOOK_ENDPOINTS = new RegExp(
|
|||
async function checkDevAppLocks(ctx) {
|
||||
const appId = ctx.appId
|
||||
|
||||
// if any public usage, don't proceed
|
||||
if (!ctx.user._id && !ctx.user.userId) {
|
||||
return
|
||||
}
|
||||
|
||||
// not a development app, don't need to do anything
|
||||
if (!appId || !appId.startsWith(APP_DEV_PREFIX)) {
|
||||
return
|
||||
|
|
|
@ -108,6 +108,7 @@ describe("Authorization middleware", () => {
|
|||
|
||||
it("passes on to next() middleware if user is an admin", async () => {
|
||||
config.setUser({
|
||||
_id: "user",
|
||||
role: {
|
||||
_id: "ADMIN",
|
||||
}
|
||||
|
|
|
@ -5,13 +5,6 @@
|
|||
const component = getContext("component")
|
||||
|
||||
export let logoUrl
|
||||
|
||||
const logOut = async () => {
|
||||
if ($builderStore.inBuilder) {
|
||||
return
|
||||
}
|
||||
await authStore.actions.logOut()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="nav" use:styleable={$component.styles}>
|
||||
|
@ -21,9 +14,6 @@
|
|||
<img class="logo" alt="logo" src={logoUrl} height="48" />
|
||||
{/if}
|
||||
</a>
|
||||
<div class="nav__controls">
|
||||
<div on:click={logOut}>Log out</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav__menu">
|
||||
<slot />
|
||||
|
|
|
@ -33,6 +33,10 @@ const PUBLIC_ENDPOINTS = [
|
|||
route: "/api/admin/configs/checklist",
|
||||
method: "GET",
|
||||
},
|
||||
{
|
||||
route: "/api/apps",
|
||||
method: "GET",
|
||||
},
|
||||
]
|
||||
|
||||
const router = new Router()
|
||||
|
|
Loading…
Reference in New Issue