Merge remote-tracking branch 'origin/develop' into feature/foreach-block

This commit is contained in:
Peter Clement 2022-04-11 10:21:08 +01:00
commit d4ff168ae4
26 changed files with 170 additions and 82 deletions

View File

@ -1,5 +1,5 @@
{
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"npmClient": "yarn",
"packages": [
"packages/*"

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/backend-core",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Budibase backend core libraries used in server and worker",
"main": "src/index.js",
"author": "Budibase",

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"license": "MPL-2.0",
"svelte": "src/index.js",
"module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
],
"dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "^1.0.105-alpha.8",
"@budibase/string-templates": "^1.0.105-alpha.9",
"@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2",

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/builder",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"license": "GPL-3.0",
"private": true,
"scripts": {
@ -65,10 +65,10 @@
}
},
"dependencies": {
"@budibase/bbui": "^1.0.105-alpha.8",
"@budibase/client": "^1.0.105-alpha.8",
"@budibase/frontend-core": "^1.0.105-alpha.8",
"@budibase/string-templates": "^1.0.105-alpha.8",
"@budibase/bbui": "^1.0.105-alpha.9",
"@budibase/client": "^1.0.105-alpha.9",
"@budibase/frontend-core": "^1.0.105-alpha.9",
"@budibase/string-templates": "^1.0.105-alpha.9",
"@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1",

View File

@ -2,9 +2,15 @@ export default function (url) {
return url
.split("/")
.map(part => {
// if parameter, then use as is
if (part.startsWith(":")) return part
return encodeURIComponent(part.replace(/ /g, "-"))
part = decodeURIComponent(part)
part = part.replace(/ /g, "-")
// If parameter, then use as is
if (!part.startsWith(":")) {
part = encodeURIComponent(part)
}
return part
})
.join("/")
.toLowerCase()

View File

@ -6,15 +6,10 @@
export let overlayEnabled = true
let imageError = false
let imageLoaded = false
const imageRenderError = () => {
imageError = true
}
const imageLoadSuccess = () => {
imageLoaded = true
}
</script>
<div class="template-card" style="background-color:{backgroundColour};">
@ -23,8 +18,7 @@
alt={name}
src={imageSrc}
on:error={imageRenderError}
on:load={imageLoadSuccess}
class={`${imageLoaded ? "loaded" : ""}`}
class:error={imageError}
/>
<div style={`display:${imageError ? "block" : "none"}`}>
<svg
@ -104,15 +98,14 @@
width: 100%;
}
.template-card img.loaded {
display: block;
}
.template-card img {
display: none;
display: block;
max-width: 100%;
border-radius: var(--border-radius-s) 0px var(--border-radius-s) 0px;
}
.template-card img.error {
display: none;
}
.template-card:hover {
background: var(--spectrum-alias-background-color-tertiary);

View File

@ -3,13 +3,14 @@
import PathTree from "./PathTree.svelte"
let routes = {}
$: paths = Object.keys(routes || {}).sort()
let paths = []
$: {
const allRoutes = $store.routes
$: allRoutes = $store.routes
$: selectedScreenId = $store.selectedScreenId
$: updatePaths(allRoutes, $selectedAccessRole, selectedScreenId)
const updatePaths = (allRoutes, selectedRoleId, selectedScreenId) => {
const sortedPaths = Object.keys(allRoutes || {}).sort()
const selectedRoleId = $selectedAccessRole
const selectedScreenId = $store.selectedScreenId
let found = false
let firstValidScreenId
@ -41,11 +42,15 @@
})
})
})
routes = filteredRoutes
routes = { ...filteredRoutes }
paths = Object.keys(routes || {}).sort()
// Select the correct role for the current screen ID
if (!found && screenRoleId) {
selectedAccessRole.set(screenRoleId)
if (screenRoleId !== selectedRoleId) {
updatePaths(allRoutes, screenRoleId, selectedScreenId)
}
}
// If the selected screen isn't in this filtered list, select the first one

View File

@ -19,7 +19,7 @@
.filter(a => a.definition.trigger?.stepId === "APP")
.map(automation => {
const schema = Object.entries(
automation.definition.trigger.inputs.fields
automation.definition.trigger.inputs.fields || {}
).map(([name, type]) => ({ name, type }))
return {

View File

@ -3,6 +3,7 @@
import { roles } from "stores/backend"
export let value
export let error
</script>
<Select
@ -11,4 +12,5 @@
options={$roles}
getOptionLabel={role => role.name}
getOptionValue={role => role._id}
{error}
/>

View File

@ -8,14 +8,50 @@
import { currentAsset, store } from "builderStore"
import { FrontendTypes } from "constants"
import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl"
import { allScreens, selectedAccessRole } from "builderStore"
export let componentInstance
export let bindings
function setAssetProps(name, value, parser) {
if (parser && typeof parser === "function") {
let errors = {}
const routeTaken = url => {
const roleId = get(selectedAccessRole) || "BASIC"
return get(allScreens).some(
screen =>
screen.routing.route.toLowerCase() === url.toLowerCase() &&
screen.routing.roleId === roleId
)
}
const roleTaken = roleId => {
const url = get(currentAsset)?.routing.route
return get(allScreens).some(
screen =>
screen.routing.route.toLowerCase() === url.toLowerCase() &&
screen.routing.roleId === roleId
)
}
const setAssetProps = (name, value, parser, validate) => {
if (parser) {
value = parser(value)
}
if (validate) {
const error = validate(value)
errors = {
...errors,
[name]: error,
}
if (error) {
return
}
} else {
errors = {
...errors,
[name]: null,
}
}
const selectedAsset = get(currentAsset)
store.update(state => {
@ -38,7 +74,6 @@
}
const screenSettings = [
// { key: "description", label: "Description", control: Input },
{
key: "routing.route",
label: "Route",
@ -49,8 +84,26 @@
}
return sanitizeUrl(val)
},
validate: val => {
const exisingValue = get(currentAsset)?.routing.route
if (val !== exisingValue && routeTaken(val)) {
return "That URL is already in use for this role"
}
return null
},
},
{
key: "routing.roleId",
label: "Access",
control: RoleSelect,
validate: val => {
const exisingValue = get(currentAsset)?.routing.roleId
if (val !== exisingValue && roleTaken(val)) {
return "That role is already in use for this URL"
}
return null
},
},
{ key: "routing.roleId", label: "Access", control: RoleSelect },
{ key: "layoutId", label: "Layout", control: LayoutSelect },
]
</script>
@ -62,9 +115,11 @@
control={def.control}
label={def.label}
key={def.key}
error="asdasds"
value={deepGet($currentAsset, def.key)}
onChange={val => setAssetProps(def.key, val, def.parser)}
onChange={val => setAssetProps(def.key, val, def.parser, def.validate)}
{bindings}
props={{ error: errors[def.key] }}
/>
{/each}
</DetailSummary>

View File

@ -15,7 +15,7 @@
import { onMount } from "svelte"
import { templates } from "stores/portal"
let loaded = false
let loaded = $templates?.length
let template
let creationModal = false
let creatingApp = false

View File

@ -40,7 +40,7 @@
let unpublishModal
let iconModal
let creatingApp = false
let loaded = false
let loaded = $apps?.length || $templates?.length
let searchTerm = ""
let cloud = $admin.cloud
let appName = ""
@ -292,8 +292,8 @@
<div class="title">
<div class="welcome">
<Layout noPadding gap="XS">
<Heading size="M">{welcomeHeader}</Heading>
<Body size="S">
<Heading size="L">{welcomeHeader}</Heading>
<Body size="M">
{welcomeBody}
</Body>
</Layout>
@ -301,7 +301,7 @@
<div class="buttons">
<Button
dataCy="create-app-btn"
size="L"
size="M"
icon="Add"
cta
on:click={initiateAppCreation}
@ -311,7 +311,7 @@
{#if $apps?.length > 0}
<Button
icon="Experience"
size="L"
size="M"
quiet
secondary
on:click={$goto("/builder/portal/apps/templates")}
@ -348,7 +348,7 @@
{#if enrichedApps.length}
<Layout noPadding gap="S">
<div class="title">
<Detail size="L">My apps</Detail>
<Detail size="L">Apps</Detail>
{#if enrichedApps.length > 1}
<div class="app-actions">
{#if cloud}

View File

@ -5,7 +5,7 @@
import { onMount } from "svelte"
import { templates } from "stores/portal"
let loaded = false
let loaded = $templates?.length
onMount(async () => {
try {

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/cli",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js",
"bin": {

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/client",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"license": "MPL-2.0",
"module": "dist/budibase-client.js",
"main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw"
},
"dependencies": {
"@budibase/bbui": "^1.0.105-alpha.8",
"@budibase/frontend-core": "^1.0.105-alpha.8",
"@budibase/string-templates": "^1.0.105-alpha.8",
"@budibase/bbui": "^1.0.105-alpha.9",
"@budibase/frontend-core": "^1.0.105-alpha.9",
"@budibase/string-templates": "^1.0.105-alpha.9",
"@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3",

View File

@ -102,7 +102,7 @@
white-space: nowrap;
}
.spectrum-Card-footer {
word-wrap: anywhere;
word-wrap: break-word;
white-space: pre-wrap;
}
.horizontal .spectrum-Card-coverPhoto {

View File

@ -125,7 +125,11 @@
{#if schemaLoaded}
<Block>
<div class="card-list" use:styleable={$component.styles}>
<BlockComponent type="form" bind:id={formId} props={{ dataSource }}>
<BlockComponent
type="form"
bind:id={formId}
props={{ dataSource, disableValidation: true }}
>
{#if title || enrichedSearchColumns?.length || showTitleButton}
<div class="header" class:mobile={$context.device.mobile}>
<div class="title">

View File

@ -106,7 +106,11 @@
{#if schemaLoaded}
<Block>
<div class={size} use:styleable={$component.styles}>
<BlockComponent type="form" bind:id={formId} props={{ dataSource }}>
<BlockComponent
type="form"
bind:id={formId}
props={{ dataSource, disableValidation: true }}
>
{#if title || enrichedSearchColumns?.length || showTitleButton}
<div class="header" class:mobile={$context.device.mobile}>
<div class="title">

View File

@ -34,7 +34,7 @@
color: var(--spectrum-global-color-gray-700) !important;
}
div :global(.apexcharts-datalabel) {
fill: var(--spectrum-global-color-gray-800);
fill: white;
}
div :global(.apexcharts-tooltip) {
background-color: var(--spectrum-global-color-gray-200) !important;
@ -45,4 +45,12 @@
background-color: var(--spectrum-global-color-gray-100) !important;
border-color: var(--spectrum-global-color-gray-300) !important;
}
div :global(.apexcharts-theme-dark .apexcharts-tooltip-text) {
color: white;
}
div
:global(.apexcharts-theme-dark
.apexcharts-tooltip-series-group.apexcharts-active) {
padding-bottom: 0;
}
</style>

View File

@ -9,6 +9,10 @@
export let disabled = false
export let actionType = "Create"
// Not exposed as a builder setting. Used internally to disable validation
// for fields rendered in things like search blocks.
export let disableValidation = false
const context = getContext("context")
const { API, fetchDatasourceSchema } = getContext("sdk")
@ -102,6 +106,7 @@
{schema}
{table}
{initialValues}
{disableValidation}
>
<slot />
</InnerForm>

View File

@ -10,6 +10,7 @@
export let size
export let schema
export let table
export let disableValidation = false
const component = getContext("component")
const { styleable, Provider, ActionTypes } = getContext("sdk")
@ -141,12 +142,14 @@
// Create validation function based on field schema
const schemaConstraints = schema?.[field]?.constraints
const validator = createValidatorFromConstraints(
schemaConstraints,
validationRules,
field,
table
)
const validator = disableValidation
? null
: createValidatorFromConstraints(
schemaConstraints,
validationRules,
field,
table
)
// If we've already registered this field then keep some existing state
let initialValue = Helpers.deepGet(initialValues, field) ?? defaultValue
@ -164,7 +167,7 @@
// If this field has already been registered and we previously had an
// error set, then re-run the validator to see if we can unset it
if (fieldState.error) {
initialError = validator(initialValue)
initialError = validator?.(initialValue)
}
}
@ -254,7 +257,7 @@
}
// Update field state
const error = validator ? validator(value) : null
const error = validator?.(value)
fieldInfo.update(state => {
state.fieldState.value = value
state.fieldState.error = error
@ -288,12 +291,14 @@
// Create new validator
const schemaConstraints = schema?.[field]?.constraints
const validator = createValidatorFromConstraints(
schemaConstraints,
validationRules,
field,
table
)
const validator = disableValidation
? null
: createValidatorFromConstraints(
schemaConstraints,
validationRules,
field,
table
)
// Update validator
fieldInfo.update(state => {

View File

@ -329,13 +329,13 @@ export const enrichButtonActions = (actions, context) => {
return actions
}
// Button context is built up as actions are executed.
// Inherit any previous button context which may have come from actions
// before a confirmable action since this breaks the chain.
let buttonContext = context.actions || []
const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]])
return async eventContext => {
// Button context is built up as actions are executed.
// Inherit any previous button context which may have come from actions
// before a confirmable action since this breaks the chain.
let buttonContext = context.actions || []
for (let i = 0; i < handlers.length; i++) {
try {
// Skip any non-existent action definitions
@ -346,6 +346,7 @@ export const enrichButtonActions = (actions, context) => {
// Built total context for this action
const totalContext = {
...context,
state: get(stateStore),
actions: buttonContext,
eventContext,
}

View File

@ -1,12 +1,12 @@
{
"name": "@budibase/frontend-core",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase",
"license": "MPL-2.0",
"svelte": "src/index.js",
"dependencies": {
"@budibase/bbui": "^1.0.105-alpha.8",
"@budibase/bbui": "^1.0.105-alpha.9",
"lodash": "^4.17.21",
"svelte": "^3.46.2"
}

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/server",
"email": "hi@budibase.com",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Budibase Web Server",
"main": "src/index.ts",
"repository": {
@ -68,9 +68,9 @@
"license": "GPL-3.0",
"dependencies": {
"@apidevtools/swagger-parser": "^10.0.3",
"@budibase/backend-core": "^1.0.105-alpha.8",
"@budibase/client": "^1.0.105-alpha.8",
"@budibase/string-templates": "^1.0.105-alpha.8",
"@budibase/backend-core": "^1.0.105-alpha.9",
"@budibase/client": "^1.0.105-alpha.9",
"@budibase/string-templates": "^1.0.105-alpha.9",
"@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0",

View File

@ -1,6 +1,6 @@
{
"name": "@budibase/string-templates",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs",
"module": "dist/bundle.mjs",

View File

@ -1,7 +1,7 @@
{
"name": "@budibase/worker",
"email": "hi@budibase.com",
"version": "1.0.105-alpha.8",
"version": "1.0.105-alpha.9",
"description": "Budibase background service",
"main": "src/index.ts",
"repository": {
@ -31,8 +31,8 @@
"author": "Budibase",
"license": "GPL-3.0",
"dependencies": {
"@budibase/backend-core": "^1.0.105-alpha.8",
"@budibase/string-templates": "^1.0.105-alpha.8",
"@budibase/backend-core": "^1.0.105-alpha.9",
"@budibase/string-templates": "^1.0.105-alpha.9",
"@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0",