Merge pull request #1234 from Budibase/lab-day-cheeks

Useful features and fixes from lab day
This commit is contained in:
Andrew Kingston 2021-03-03 02:16:57 -08:00 committed by GitHub
commit f20e5e28fd
14 changed files with 228 additions and 8 deletions

View File

@ -120,7 +120,7 @@ const getContextBindings = (asset, componentId) => {
tableName = info.table?.name tableName = info.table?.name
// Add _id and _rev fields for certain types // Add _id and _rev fields for certain types
if (datasource.type === "table" || datasource.type === "link") { if (schema && ["table", "link"].includes(datasource.type)) {
schema["_id"] = { type: "string" } schema["_id"] = { type: "string" }
schema["_rev"] = { type: "string" } schema["_rev"] = { type: "string" }
} }

View File

@ -12,6 +12,7 @@
"fieldgroup", "fieldgroup",
"stringfield", "stringfield",
"numberfield", "numberfield",
"passwordfield",
"optionsfield", "optionsfield",
"booleanfield", "booleanfield",
"longformfield", "longformfield",
@ -49,6 +50,7 @@
"heading", "heading",
"text", "text",
"image", "image",
"backgroundimage",
"link", "link",
"icon", "icon",
"embed" "embed"

View File

@ -0,0 +1,36 @@
<script>
import { Label } from "@budibase/bbui"
import { getBindableProperties } from "builderStore/dataBinding"
import { currentAsset, store } from "builderStore"
import DrawerBindableInput from "components/common/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 auto 1fr;
align-items: baseline;
}
</style>

View File

@ -0,0 +1,7 @@
<div class="root">This action doesn't require any additional settings.</div>
<style>
.root {
font-size: var(--font-size-s);
}
</style>

View File

@ -4,6 +4,8 @@ import DeleteRow from "./DeleteRow.svelte"
import ExecuteQuery from "./ExecuteQuery.svelte" import ExecuteQuery from "./ExecuteQuery.svelte"
import TriggerAutomation from "./TriggerAutomation.svelte" import TriggerAutomation from "./TriggerAutomation.svelte"
import ValidateForm from "./ValidateForm.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 // defines what actions are available, when adding a new one
// the component is the setup panel for the action // the component is the setup panel for the action
@ -35,4 +37,12 @@ export default [
name: "Validate Form", name: "Validate Form",
component: ValidateForm, component: ValidateForm,
}, },
{
name: "Log In",
component: LogIn,
},
{
name: "Log Out",
component: LogOut,
},
] ]

View File

@ -11,6 +11,7 @@
screenStore, screenStore,
authStore, authStore,
} from "../store" } from "../store"
import { TableNames, ActionTypes } from "../constants"
// Provide contexts // Provide contexts
setContext("sdk", SDK) setContext("sdk", SDK)
@ -25,10 +26,20 @@
await authStore.actions.fetchUser() await authStore.actions.fetchUser()
loaded = true loaded = true
}) })
// Register this as a refreshable datasource so that user changes cause
// the user object to be refreshed
$: actions = [
{
type: ActionTypes.RefreshDatasource,
callback: () => authStore.actions.fetchUser(),
metadata: { datasource: { type: "table", tableId: TableNames.USERS } },
},
]
</script> </script>
{#if loaded && $screenStore.activeLayout} {#if loaded && $screenStore.activeLayout}
<Provider key="user" data={$authStore}> <Provider key="user" data={$authStore} {actions}>
<Component definition={$screenStore.activeLayout.props} /> <Component definition={$screenStore.activeLayout.props} />
<NotificationDisplay /> <NotificationDisplay />
</Provider> </Provider>

View File

@ -21,7 +21,7 @@ const createAuthStore = () => {
const logIn = async ({ email, password }) => { const logIn = async ({ email, password }) => {
const user = await API.logIn({ email, password }) const user = await API.logIn({ email, password })
if (!user.error) { if (!user.error) {
store.set(user) await fetchUser()
await initialise() await initialise()
goToDefaultRoute() goToDefaultRoute()
} }

View File

@ -1,5 +1,5 @@
import { get } from "svelte/store" import { get } from "svelte/store"
import { routeStore, builderStore } from "../store" import { routeStore, builderStore, authStore } from "../store"
import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api" import { saveRow, deleteRow, executeQuery, triggerAutomation } from "../api"
import { ActionTypes } from "../constants" import { ActionTypes } from "../constants"
@ -68,6 +68,15 @@ const refreshDatasourceHandler = async (action, context) => {
) )
} }
const loginHandler = async action => {
const { email, password } = action.parameters
await authStore.actions.logIn({ email, password })
}
const logoutHandler = async () => {
await authStore.actions.logOut()
}
const handlerMap = { const handlerMap = {
["Save Row"]: saveRowHandler, ["Save Row"]: saveRowHandler,
["Delete Row"]: deleteRowHandler, ["Delete Row"]: deleteRowHandler,
@ -76,6 +85,8 @@ const handlerMap = {
["Trigger Automation"]: triggerAutomationHandler, ["Trigger Automation"]: triggerAutomationHandler,
["Validate Form"]: validateFormHandler, ["Validate Form"]: validateFormHandler,
["Refresh Datasource"]: refreshDatasourceHandler, ["Refresh Datasource"]: refreshDatasourceHandler,
["Log In"]: loginHandler,
["Log Out"]: logoutHandler,
} }
/** /**

View File

@ -294,6 +294,63 @@
} }
] ]
}, },
"backgroundimage": {
"name": "Background Image",
"description": "A background image",
"icon": "ri-image-line",
"styleable": true,
"settings": [
{
"type": "text",
"label": "URL",
"key": "url"
},
{
"type": "select",
"label": "Position",
"key": "position",
"defaultValue": "center center",
"options": [
{
"label": "Center Top",
"value": "center top"
},
{
"label": "Center",
"value": "center center"
},
{
"label": "Center Bottom",
"value": "center bottom"
},
{
"label": "Left Top",
"value": "left top"
},
{
"label": "Left Center",
"value": "left center"
},
{
"label": "Left Bottom",
"value": "left bottom"
},
{
"label": "Right Top",
"value": "right top"
},
{
"label": "Right Center",
"value": "right center"
},
{
"label": "Right Bottom",
"value": "right bottom"
}
]
}
]
},
"icon": { "icon": {
"name": "Icon", "name": "Icon",
"description": "A basic component for displaying icons", "description": "A basic component for displaying icons",
@ -394,6 +451,11 @@
"type": "boolean", "type": "boolean",
"label": "New Tab", "label": "New Tab",
"key": "openInNewTab" "key": "openInNewTab"
},
{
"type": "boolean",
"label": "External",
"key": "external"
} }
] ]
}, },
@ -1233,6 +1295,34 @@
} }
] ]
}, },
"passwordfield": {
"name": "Password Field",
"icon": "ri-lock-password-line",
"styleable": true,
"settings": [
{
"type": "field/string",
"label": "Field",
"key": "field"
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "text",
"label": "Placeholder",
"key": "placeholder"
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
}
]
},
"optionsfield": { "optionsfield": {
"name": "Options Picker", "name": "Options Picker",
"icon": "ri-file-list-line", "icon": "ri-file-list-line",

View File

@ -0,0 +1,38 @@
<script>
import { getContext } from "svelte"
const { styleable } = getContext("sdk")
const component = getContext("component")
export let url
export let position
let style = ""
$: {
if (url) {
style += `background-image: url("${url}");`
}
if (position) {
style += `background-position: ${position};`
}
}
</script>
<div class="outer" use:styleable={$component.styles}>
<div class="inner" {style} />
</div>
<style>
.outer {
position: relative;
}
.inner {
position: absolute;
height: 100%;
width: 100%;
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
}
</style>

View File

@ -7,11 +7,19 @@
export let url = "" export let url = ""
export let text = "" export let text = ""
export let openInNewTab = false export let openInNewTab = false
export let external = false
$: target = openInNewTab ? "_blank" : "_self" $: target = openInNewTab ? "_blank" : "_self"
</script> </script>
<a href={url || '/'} use:linkable {target} use:styleable={$component.styles}> {#if external}
{text} <a href={url || '/'} {target} use:styleable={$component.styles}>
<slot /> {text}
</a> <slot />
</a>
{:else}
<a href={url || '/'} use:linkable {target} use:styleable={$component.styles}>
{text}
<slot />
</a>
{/if}

View File

@ -0,0 +1,5 @@
<script>
import StringField from "./StringField.svelte"
</script>
<StringField {...$$props} type="password" />

View File

@ -8,3 +8,4 @@ export { default as longformfield } from "./LongFormField.svelte"
export { default as datetimefield } from "./DateTimeField.svelte" export { default as datetimefield } from "./DateTimeField.svelte"
export { default as attachmentfield } from "./AttachmentField.svelte" export { default as attachmentfield } from "./AttachmentField.svelte"
export { default as relationshipfield } from "./RelationshipField.svelte" export { default as relationshipfield } from "./RelationshipField.svelte"
export { default as passwordfield } from "./PasswordField.svelte"

View File

@ -31,5 +31,6 @@ export { default as cardhorizontal } from "./CardHorizontal.svelte"
export { default as cardstat } from "./CardStat.svelte" export { default as cardstat } from "./CardStat.svelte"
export { default as icon } from "./Icon.svelte" export { default as icon } from "./Icon.svelte"
export { default as search } from "./Search.svelte" export { default as search } from "./Search.svelte"
export { default as backgroundimage } from "./BackgroundImage.svelte"
export * from "./charts" export * from "./charts"
export * from "./forms" export * from "./forms"