chore: resolved merge conflicts from develop branch

This commit is contained in:
Vinoth Kirubakaran 2022-04-22 15:30:43 +05:30
commit e2ea748ce6
39 changed files with 630 additions and 165 deletions

View File

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

View File

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

View File

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

View File

@ -80,8 +80,4 @@
.active svg { .active svg {
color: var(--spectrum-global-color-blue-600); color: var(--spectrum-global-color-blue-600);
} }
.spectrum-ActionButton-label {
padding-bottom: 2px;
}
</style> </style>

View File

@ -36,6 +36,7 @@
export let disableSorting = false export let disableSorting = false
export let autoSortColumns = true export let autoSortColumns = true
export let compact = false export let compact = false
export let customPlaceholder = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -387,13 +388,24 @@
</div> </div>
{/each} {/each}
{:else} {:else}
<div class="placeholder" class:placeholder--no-fields={!fields?.length}> <div
class="placeholder"
class:placeholder--custom={customPlaceholder}
class:placeholder--no-fields={!fields?.length}
>
{#if customPlaceholder}
<slot name="placeholder" />
{:else}
<div class="placeholder-content"> <div class="placeholder-content">
<svg class="spectrum-Icon spectrum-Icon--sizeXXL" focusable="false"> <svg
class="spectrum-Icon spectrum-Icon--sizeXXL"
focusable="false"
>
<use xlink:href="#spectrum-icon-18-Table" /> <use xlink:href="#spectrum-icon-18-Table" />
</svg> </svg>
<div>No rows found</div> <div>No rows found</div>
</div> </div>
{/if}
</div> </div>
{/if} {/if}
</div> </div>
@ -458,6 +470,13 @@
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
user-select: none; user-select: none;
border-top: var(--table-border);
}
.spectrum-Table-headCell:first-of-type {
border-left: var(--table-border);
}
.spectrum-Table-headCell:last-of-type {
border-right: var(--table-border);
} }
.spectrum-Table-headCell--alignCenter { .spectrum-Table-headCell--alignCenter {
justify-content: center; justify-content: center;
@ -576,16 +595,19 @@
border-top: none; border-top: none;
grid-column: 1 / -1; grid-column: 1 / -1;
background-color: var(--table-bg); background-color: var(--table-bg);
padding: 40px;
} }
.placeholder--no-fields { .placeholder--no-fields {
border-top: var(--table-border); border-top: var(--table-border);
} }
.placeholder--custom {
justify-content: flex-start;
}
.wrapper--quiet .placeholder { .wrapper--quiet .placeholder {
border-left: none; border-left: none;
border-right: none; border-right: none;
} }
.placeholder-content { .placeholder-content {
padding: 40px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;

View File

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

View File

@ -654,7 +654,7 @@ export const getSchemaForDatasource = (asset, datasource, options) => {
* Builds a form schema given a form component. * Builds a form schema given a form component.
* A form schema is a schema of all the fields nested anywhere within a form. * A form schema is a schema of all the fields nested anywhere within a form.
*/ */
const buildFormSchema = component => { export const buildFormSchema = component => {
let schema = {} let schema = {}
if (!component) { if (!component) {
return schema return schema

View File

@ -14,7 +14,7 @@
import Table from "./Table.svelte" import Table from "./Table.svelte"
import { TableNames } from "constants" import { TableNames } from "constants"
import CreateEditRow from "./modals/CreateEditRow.svelte" import CreateEditRow from "./modals/CreateEditRow.svelte"
import { Pagination } from "@budibase/bbui" import { Pagination, Heading, Body, Layout } from "@budibase/bbui"
import { fetchData } from "@budibase/frontend-core" import { fetchData } from "@budibase/frontend-core"
import { API } from "api" import { API } from "api"
@ -27,6 +27,8 @@
$: enrichedSchema = enrichSchema($tables.selected?.schema) $: enrichedSchema = enrichSchema($tables.selected?.schema)
$: id = $tables.selected?._id $: id = $tables.selected?._id
$: fetch = createFetch(id) $: fetch = createFetch(id)
$: hasCols = checkHasCols(schema)
$: hasRows = !!$fetch.rows?.length
const enrichSchema = schema => { const enrichSchema = schema => {
let tempSchema = { ...schema } let tempSchema = { ...schema }
@ -47,6 +49,20 @@
return tempSchema return tempSchema
} }
const checkHasCols = schema => {
if (!schema || Object.keys(schema).length === 0) {
return false
}
let fields = Object.values(schema)
for (let field of fields) {
if (!field.autocolumn) {
return true
}
}
return false
}
// Fetches new data whenever the table changes // Fetches new data whenever the table changes
const createFetch = tableId => { const createFetch = tableId => {
return fetchData({ return fetchData({
@ -104,19 +120,28 @@
disableSorting disableSorting
on:updatecolumns={onUpdateColumns} on:updatecolumns={onUpdateColumns}
on:updaterows={onUpdateRows} on:updaterows={onUpdateRows}
customPlaceholder
> >
<CreateColumnButton on:updatecolumns={onUpdateColumns} /> <div class="buttons">
{#if schema && Object.keys(schema).length > 0} <div class="left-buttons">
<CreateColumnButton
highlighted={$fetch.loaded && (!hasCols || !hasRows)}
on:updatecolumns={onUpdateColumns}
/>
{#if !isUsersTable} {#if !isUsersTable}
<CreateRowButton <CreateRowButton
on:updaterows={onUpdateRows} on:updaterows={onUpdateRows}
title={"Create row"} title={"Create row"}
modalContentComponent={CreateEditRow} modalContentComponent={CreateEditRow}
disabled={!hasCols}
highlighted={$fetch.loaded && hasCols && !hasRows}
/> />
{/if} {/if}
{#if isInternal} {#if isInternal}
<CreateViewButton /> <CreateViewButton disabled={!hasCols || !hasRows} />
{/if} {/if}
</div>
<div class="right-buttons">
<ManageAccessButton resourceId={$tables.selected?._id} /> <ManageAccessButton resourceId={$tables.selected?._id} />
{#if isUsersTable} {#if isUsersTable}
<EditRolesButton /> <EditRolesButton />
@ -128,16 +153,40 @@
/> />
{/if} {/if}
<HideAutocolumnButton bind:hideAutocolumns /> <HideAutocolumnButton bind:hideAutocolumns />
<!-- always have the export last -->
<ExportButton view={$tables.selected?._id} />
<ImportButton <ImportButton
tableId={$tables.selected?._id} tableId={$tables.selected?._id}
on:updaterows={onUpdateRows} on:updaterows={onUpdateRows}
/> />
<ExportButton
disabled={!hasRows || !hasCols}
view={$tables.selected?._id}
/>
{#key id} {#key id}
<TableFilterButton {schema} on:change={onFilter} /> <TableFilterButton
{schema}
on:change={onFilter}
disabled={!hasCols || !hasRows}
/>
{/key} {/key}
</div>
</div>
<div slot="placeholder">
<Layout gap="S">
{#if !hasCols}
<Heading>Let's create some columns</Heading>
<Body>
Start building out your table structure<br />
by adding some columns
</Body>
{:else}
<Heading>Now let's add a row</Heading>
<Body>
Add some data to your table<br />
by adding some rows
</Body>
{/if} {/if}
</Layout>
</div>
</Table> </Table>
{#key id} {#key id}
<div in:fade={{ delay: 200, duration: 100 }}> <div in:fade={{ delay: 200, duration: 100 }}>
@ -162,4 +211,20 @@
align-items: center; align-items: center;
margin-top: var(--spacing-xl); margin-top: var(--spacing-xl);
} }
.buttons {
flex: 1 1 auto;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.left-buttons,
.right-buttons {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-m);
}
</style> </style>

View File

@ -25,6 +25,7 @@
export let rowCount export let rowCount
export let type export let type
export let disableSorting = false export let disableSorting = false
export let customPlaceholder = false
let selectedRows = [] let selectedRows = []
let editableColumn let editableColumn
@ -117,10 +118,10 @@
</script> </script>
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<div> <Layout noPadding gap="XS">
{#if title} {#if title}
<div class="table-title"> <div class="table-title">
<Heading size="S">{title}</Heading> <Heading size="M">{title}</Heading>
{#if loading} {#if loading}
<div transition:fade|local> <div transition:fade|local>
<Spinner size="10" /> <Spinner size="10" />
@ -134,7 +135,7 @@
<DeleteRowsButton on:updaterows {selectedRows} {deleteRows} /> <DeleteRowsButton on:updaterows {selectedRows} {deleteRows} />
{/if} {/if}
</div> </div>
</div> </Layout>
{#key tableId} {#key tableId}
<div class="table-wrapper"> <div class="table-wrapper">
<Table <Table
@ -144,6 +145,7 @@
{customRenderers} {customRenderers}
{rowCount} {rowCount}
{disableSorting} {disableSorting}
{customPlaceholder}
bind:selectedRows bind:selectedRows
allowSelectRows={allowEditing && !isUsersTable} allowSelectRows={allowEditing && !isUsersTable}
allowEditRows={allowEditing} allowEditRows={allowEditing}
@ -153,7 +155,9 @@
on:editrow={e => editRow(e.detail)} on:editrow={e => editRow(e.detail)}
on:clickrelationship={e => selectRelationship(e.detail)} on:clickrelationship={e => selectRelationship(e.detail)}
on:sort on:sort
/> >
<slot slot="placeholder" name="placeholder" />
</Table>
</div> </div>
{/key} {/key}
</Layout> </Layout>
@ -176,6 +180,7 @@
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
margin-top: var(--spacing-m);
} }
.table-title > div { .table-title > div {
margin-left: var(--spacing-xs); margin-left: var(--spacing-xs);

View File

@ -2,10 +2,21 @@
import { ActionButton, Modal } from "@budibase/bbui" import { ActionButton, Modal } from "@budibase/bbui"
import CreateEditColumn from "../modals/CreateEditColumn.svelte" import CreateEditColumn from "../modals/CreateEditColumn.svelte"
export let highlighted = false
export let disabled = false
let modal let modal
</script> </script>
<ActionButton icon="TableColumnAddRight" quiet size="S" on:click={modal.show}> <ActionButton
{disabled}
selected={highlighted}
emphasized={highlighted}
icon="TableColumnAddRight"
quiet
size="S"
on:click={modal.show}
>
Create column Create column
</ActionButton> </ActionButton>
<Modal bind:this={modal}> <Modal bind:this={modal}>

View File

@ -4,11 +4,21 @@
export let modalContentComponent = CreateEditRow export let modalContentComponent = CreateEditRow
export let title = "Create row" export let title = "Create row"
export let disabled = false
export let highlighted = false
let modal let modal
</script> </script>
<ActionButton icon="TableRowAddBottom" size="S" quiet on:click={modal.show}> <ActionButton
{disabled}
emphasized={highlighted}
selected={highlighted}
icon="TableRowAddBottom"
size="S"
quiet
on:click={modal.show}
>
{title} {title}
</ActionButton> </ActionButton>
<Modal bind:this={modal}> <Modal bind:this={modal}>

View File

@ -2,10 +2,18 @@
import { Modal, ActionButton } from "@budibase/bbui" import { Modal, ActionButton } from "@budibase/bbui"
import CreateViewModal from "../modals/CreateViewModal.svelte" import CreateViewModal from "../modals/CreateViewModal.svelte"
export let disabled = false
let modal let modal
</script> </script>
<ActionButton icon="CollectionAdd" size="S" quiet on:click={modal.show}> <ActionButton
{disabled}
icon="CollectionAdd"
size="S"
quiet
on:click={modal.show}
>
Create view Create view
</ActionButton> </ActionButton>
<Modal bind:this={modal}> <Modal bind:this={modal}>

View File

@ -3,11 +3,18 @@
import ExportModal from "../modals/ExportModal.svelte" import ExportModal from "../modals/ExportModal.svelte"
export let view export let view
export let disabled = false
let modal let modal
</script> </script>
<ActionButton icon="DataDownload" size="S" quiet on:click={modal.show}> <ActionButton
{disabled}
icon="DataDownload"
size="S"
quiet
on:click={modal.show}
>
Export Export
</ActionButton> </ActionButton>
<Modal bind:this={modal}> <Modal bind:this={modal}>

View File

@ -8,6 +8,12 @@
} }
</script> </script>
<ActionButton icon="MagicWand" primary size="S" quiet on:click={hideOrUnhide}> <ActionButton
{#if hideAutocolumns}Show auto columns{:else}Hide auto columns{/if} icon={hideAutocolumns ? "VisibilityOff" : "Visibility"}
primary
size="S"
quiet
on:click={hideOrUnhide}
>
Auto columns
</ActionButton> </ActionButton>

View File

@ -5,6 +5,7 @@
export let schema export let schema
export let filters export let filters
export let disabled = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let modal let modal
@ -17,6 +18,7 @@
icon="Filter" icon="Filter"
size="S" size="S"
quiet quiet
{disabled}
on:click={modal.show} on:click={modal.show}
active={tempValue?.length > 0} active={tempValue?.length > 0}
> >

View File

@ -0,0 +1,78 @@
<script>
import { Select, Label, Combobox } from "@budibase/bbui"
import { onMount } from "svelte"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import { currentAsset, store } from "builderStore"
import {
getActionProviderComponents,
buildFormSchema,
} from "builderStore/dataBinding"
import { findComponent } from "builderStore/componentUtils"
export let parameters
export let bindings = []
const typeOptions = [
{
label: "Set value",
value: "set",
},
{
label: "Reset to default value",
value: "reset",
},
]
$: formComponent = findComponent($currentAsset.props, parameters.componentId)
$: formSchema = buildFormSchema(formComponent)
$: fieldOptions = Object.keys(formSchema || {})
$: actionProviders = getActionProviderComponents(
$currentAsset,
$store.selectedComponentId,
"ValidateForm"
)
onMount(() => {
if (!parameters.type) {
parameters.type = "set"
}
})
</script>
<div class="root">
<Label small>Form</Label>
<Select
bind:value={parameters.componentId}
options={actionProviders}
getOptionLabel={x => x._instanceName}
getOptionValue={x => x._id}
/>
<Label small>Type</Label>
<Select
placeholder={null}
bind:value={parameters.type}
options={typeOptions}
/>
<Label small>Field</Label>
<Combobox bind:value={parameters.field} options={fieldOptions} />
{#if parameters.type === "set"}
<Label small>Value</Label>
<DrawerBindableInput
{bindings}
value={parameters.value}
on:change={e => (parameters.value = e.detail)}
/>
{/if}
</div>
<style>
.root {
display: grid;
column-gap: var(--spacing-l);
row-gap: var(--spacing-s);
grid-template-columns: 60px 1fr;
align-items: center;
max-width: 400px;
margin: 0 auto;
}
</style>

View File

@ -14,3 +14,4 @@ export { default as DuplicateRow } from "./DuplicateRow.svelte"
export { default as S3Upload } from "./S3Upload.svelte" export { default as S3Upload } from "./S3Upload.svelte"
export { default as ExportData } from "./ExportData.svelte" export { default as ExportData } from "./ExportData.svelte"
export { default as ContinueIf } from "./ContinueIf.svelte" export { default as ContinueIf } from "./ContinueIf.svelte"
export { default as UpdateFieldValue } from "./UpdateFieldValue.svelte"

View File

@ -42,25 +42,29 @@
"name": "Trigger Automation", "name": "Trigger Automation",
"component": "TriggerAutomation" "component": "TriggerAutomation"
}, },
{
"name": "Update Field Value",
"component": "UpdateFieldValue"
},
{ {
"name": "Validate Form", "name": "Validate Form",
"component": "ValidateForm" "component": "ValidateForm"
}, },
{ {
"name": "Log Out", "name": "Change Form Step",
"component": "LogOut" "component": "ChangeFormStep"
}, },
{ {
"name": "Clear Form", "name": "Clear Form",
"component": "ClearForm" "component": "ClearForm"
}, },
{ {
"name": "Close Screen Modal", "name": "Log Out",
"component": "CloseScreenModal" "component": "LogOut"
}, },
{ {
"name": "Change Form Step", "name": "Close Screen Modal",
"component": "ChangeFormStep" "component": "CloseScreenModal"
}, },
{ {
"name": "Refresh Data Provider", "name": "Refresh Data Provider",

View File

@ -75,8 +75,8 @@
<div class="title"> <div class="title">
<div class="welcome"> <div class="welcome">
<Layout noPadding gap="XS"> <Layout noPadding gap="XS">
<Heading size="M">{createAppTitle}</Heading> <Heading size="L">{createAppTitle}</Heading>
<Body size="S"> <Body size="M">
{welcomeBody} {welcomeBody}
</Body> </Body>
</Layout> </Layout>
@ -84,7 +84,7 @@
<div class="buttons"> <div class="buttons">
<Button <Button
dataCy="create-app-btn" dataCy="create-app-btn"
size="L" size="M"
icon="Add" icon="Add"
cta cta
on:click={initiateAppCreation} on:click={initiateAppCreation}
@ -94,7 +94,7 @@
<Button <Button
dataCy="import-app-btn" dataCy="import-app-btn"
icon="Import" icon="Import"
size="L" size="M"
quiet quiet
secondary secondary
on:click={initiateAppImport} on:click={initiateAppImport}

View File

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

View File

@ -1834,7 +1834,12 @@
"icon": "Form", "icon": "Form",
"hasChildren": true, "hasChildren": true,
"illegalChildren": ["section", "form"], "illegalChildren": ["section", "form"],
"actions": ["ValidateForm", "ClearForm", "ChangeFormStep"], "actions": [
"ValidateForm",
"ClearForm",
"ChangeFormStep",
"UpdateFieldValue"
],
"styles": ["size"], "styles": ["size"],
"settings": [ "settings": [
{ {
@ -1975,6 +1980,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2049,6 +2065,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2089,6 +2116,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2125,6 +2163,17 @@
"key": "placeholder", "key": "placeholder",
"placeholder": "Choose an option" "placeholder": "Choose an option"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "select", "type": "select",
"label": "Type", "label": "Type",
@ -2274,6 +2323,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Autocomplete", "label": "Autocomplete",
@ -2399,6 +2459,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2439,6 +2510,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "select", "type": "select",
"label": "Formatting", "label": "Formatting",
@ -2512,6 +2594,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2657,6 +2750,17 @@
"label": "Extensions", "label": "Extensions",
"key": "extensions" "key": "extensions"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2697,6 +2801,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Autocomplete", "label": "Autocomplete",
@ -2742,6 +2857,17 @@
"label": "Default value", "label": "Default value",
"key": "defaultValue" "key": "defaultValue"
}, },
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{ {
"type": "boolean", "type": "boolean",
"label": "Disabled", "label": "Disabled",
@ -2750,6 +2876,62 @@
} }
] ]
}, },
"s3upload": {
"name": "S3 File Upload",
"info": "This component can't be used with S3 datasources that use custom endpoints.",
"icon": "UploadToCloud",
"styles": ["size"],
"editable": true,
"settings": [
{
"type": "field/attachment",
"label": "Field",
"key": "field"
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "dataSource/s3",
"label": "S3 Datasource",
"key": "datasourceId"
},
{
"type": "text",
"label": "Bucket",
"key": "bucket"
},
{
"type": "text",
"label": "File Name",
"key": "key"
},
{
"type": "event",
"label": "On Change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
},
{
"type": "validation/attachment",
"label": "Validation",
"key": "validation"
}
]
},
"dataprovider": { "dataprovider": {
"name": "Data Provider", "name": "Data Provider",
"info": "Pagination is only available for data stored in tables.", "info": "Pagination is only available for data stored in tables.",
@ -3581,51 +3763,6 @@
} }
] ]
}, },
"s3upload": {
"name": "S3 File Upload",
"info": "This component can't be used with S3 datasources that use custom endpoints.",
"icon": "UploadToCloud",
"styles": ["size"],
"editable": true,
"settings": [
{
"type": "field/attachment",
"label": "Field",
"key": "field"
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "dataSource/s3",
"label": "S3 Datasource",
"key": "datasourceId"
},
{
"type": "text",
"label": "Bucket",
"key": "bucket"
},
{
"type": "text",
"label": "File Name",
"key": "key"
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
},
{
"type": "validation/attachment",
"label": "Validation",
"key": "validation"
}
]
},
"markdownviewer": { "markdownviewer": {
"name": "Markdown Viewer", "name": "Markdown Viewer",
"icon": "TaskList", "icon": "TaskList",

View File

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

View File

@ -8,6 +8,7 @@
export let disabled = false export let disabled = false
export let validation export let validation
export let extensions export let extensions
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -38,6 +39,13 @@
return [] return []
} }
} }
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -55,9 +63,7 @@
value={fieldState.value} value={fieldState.value}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
on:change={e => { on:change={handleChange}
fieldApi.setValue(e.detail)
}}
{processFiles} {processFiles}
{handleFileTooLarge} {handleFileTooLarge}
{extensions} {extensions}

View File

@ -9,6 +9,7 @@
export let size export let size
export let validation export let validation
export let defaultValue export let defaultValue
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -25,6 +26,13 @@
} }
return false return false
} }
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -44,8 +52,8 @@
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}
{size} {size}
on:change={e => fieldApi.setValue(e.detail)}
{text} {text}
on:change={handleChange}
/> />
{/if} {/if}
</Field> </Field>

View File

@ -10,9 +10,17 @@
export let timeOnly = false export let timeOnly = false
export let validation export let validation
export let defaultValue export let defaultValue
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -28,7 +36,7 @@
{#if fieldState} {#if fieldState}
<CoreDatePicker <CoreDatePicker
value={fieldState.value} value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}

View File

@ -219,10 +219,10 @@
}) })
return valid return valid
}, },
clear: () => { reset: () => {
// Clear the form by clearing each individual field // Reset the form by resetting each individual field
fields.forEach(field => { fields.forEach(field => {
get(field).fieldApi.clearValue() get(field).fieldApi.reset()
}) })
}, },
changeStep: ({ type, number }) => { changeStep: ({ type, number }) => {
@ -241,6 +241,22 @@
currentStep.set(step) currentStep.set(step)
} }
}, },
setFieldValue: (fieldName, value) => {
const field = getField(fieldName)
if (!field) {
return
}
const { fieldApi } = get(field)
fieldApi.setValue(value)
},
resetField: fieldName => {
const field = getField(fieldName)
if (!field) {
return
}
const { fieldApi } = get(field)
fieldApi.reset()
},
} }
// Creates an API for a specific field // Creates an API for a specific field
@ -268,11 +284,11 @@
return !error return !error
} }
// Clears the value of a certain field back to the initial value // Clears the value of a certain field back to the default value
const clearValue = () => { const reset = () => {
const fieldInfo = getField(field) const fieldInfo = getField(field)
const { fieldState } = get(fieldInfo) const { fieldState } = get(fieldInfo)
const newValue = initialValues[field] ?? fieldState.defaultValue const newValue = fieldState.defaultValue
// Update field state // Update field state
fieldInfo.update(state => { fieldInfo.update(state => {
@ -329,7 +345,7 @@
return { return {
setValue, setValue,
clearValue, reset,
updateValidation, updateValidation,
setDisabled, setDisabled,
validate: () => { validate: () => {
@ -354,11 +370,20 @@
// register their fields to step 1 // register their fields to step 1
setContext("form-step", writable(1)) setContext("form-step", writable(1))
const handleUpdateFieldValue = ({ type, field, value }) => {
if (type === "set") {
formApi.setFieldValue(field, value)
} else {
formApi.resetField(field)
}
}
// Action context to pass to children // Action context to pass to children
const actions = [ const actions = [
{ type: ActionTypes.ValidateForm, callback: formApi.validate }, { type: ActionTypes.ValidateForm, callback: formApi.validate },
{ type: ActionTypes.ClearForm, callback: formApi.clear }, { type: ActionTypes.ClearForm, callback: formApi.reset },
{ type: ActionTypes.ChangeFormStep, callback: formApi.changeStep }, { type: ActionTypes.ChangeFormStep, callback: formApi.changeStep },
{ type: ActionTypes.UpdateFieldValue, callback: handleUpdateFieldValue },
] ]
</script> </script>

View File

@ -8,6 +8,7 @@
export let placeholder export let placeholder
export let disabled = false export let disabled = false
export let defaultValue = "" export let defaultValue = ""
export let onChange
const component = getContext("component") const component = getContext("component")
const validation = [ const validation = [
@ -33,6 +34,14 @@
return value return value
} }
} }
const handleChange = e => {
const value = parseValue(e.detail)
fieldApi.setValue(value)
if (onChange) {
onChange({ value })
}
}
</script> </script>
<Field <Field
@ -49,7 +58,7 @@
<div style="--height: {height};"> <div style="--height: {height};">
<CoreTextArea <CoreTextArea
value={serialiseValue(fieldState.value)} value={serialiseValue(fieldState.value)}
on:change={e => fieldApi.setValue(parseValue(e.detail))} on:change={handleChange}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}

View File

@ -11,6 +11,7 @@
export let validation export let validation
export let defaultValue = "" export let defaultValue = ""
export let format = "auto" export let format = "auto"
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -44,6 +45,13 @@
}, },
}) })
} }
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -61,7 +69,7 @@
{#if useRichText} {#if useRichText}
<CoreRichTextField <CoreRichTextField
value={fieldState.value} value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}
@ -78,7 +86,7 @@
{:else} {:else}
<CoreTextArea <CoreTextArea
value={fieldState.value} value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}

View File

@ -14,6 +14,7 @@
export let valueColumn export let valueColumn
export let customOptions export let customOptions
export let autocomplete = false export let autocomplete = false
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -34,13 +35,18 @@
if (!values) { if (!values) {
return [] return []
} }
if (Array.isArray(values)) { if (Array.isArray(values)) {
return values return values
} }
return values.split(",").map(value => value.trim()) return values.split(",").map(value => value.trim())
} }
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -62,7 +68,7 @@
getOptionValue={flatOptions ? x => x : x => x.value} getOptionValue={flatOptions ? x => x : x => x.value}
id={fieldState.fieldId} id={fieldState.fieldId}
disabled={fieldState.disabled} disabled={fieldState.disabled}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
{placeholder} {placeholder}
{options} {options}
{autocomplete} {autocomplete}

View File

@ -16,6 +16,7 @@
export let customOptions export let customOptions
export let autocomplete = false export let autocomplete = false
export let direction = "vertical" export let direction = "vertical"
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -30,6 +31,13 @@
valueColumn, valueColumn,
customOptions customOptions
) )
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -52,7 +60,7 @@
error={fieldState.error} error={fieldState.error}
{options} {options}
{placeholder} {placeholder}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
getOptionLabel={flatOptions ? x => x : x => x.label} getOptionLabel={flatOptions ? x => x : x => x.label}
getOptionValue={flatOptions ? x => x : x => x.value} getOptionValue={flatOptions ? x => x : x => x.value}
{autocomplete} {autocomplete}
@ -66,7 +74,7 @@
error={fieldState.error} error={fieldState.error}
{options} {options}
{direction} {direction}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
getOptionLabel={flatOptions ? x => x : x => x.label} getOptionLabel={flatOptions ? x => x : x => x.label}
getOptionValue={flatOptions ? x => x : x => x.value} getOptionValue={flatOptions ? x => x : x => x.value}
/> />

View File

@ -13,6 +13,7 @@
export let validation export let validation
export let autocomplete = false export let autocomplete = false
export let defaultValue export let defaultValue
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -62,11 +63,11 @@
} }
const singleHandler = e => { const singleHandler = e => {
fieldApi.setValue(e.detail == null ? [] : [e.detail]) handleChange(e.detail == null ? [] : [e.detail])
} }
const multiHandler = e => { const multiHandler = e => {
fieldApi.setValue(e.detail) handleChange(e.detail)
} }
const expand = values => { const expand = values => {
@ -78,6 +79,13 @@
} }
return values.split(",").map(value => value.trim()) return values.split(",").map(value => value.trim())
} }
const handleChange = value => {
fieldApi.setValue(value)
if (onChange) {
onChange({ value })
}
}
</script> </script>
<Field <Field

View File

@ -10,6 +10,7 @@
export let label export let label
export let disabled = false export let disabled = false
export let validation export let validation
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
@ -88,6 +89,13 @@
} }
} }
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
onMount(() => { onMount(() => {
uploadStore.actions.registerFileUpload($component.id, upload) uploadStore.actions.registerFileUpload($component.id, upload)
}) })
@ -113,9 +121,7 @@
value={fieldState.value} value={fieldState.value}
disabled={loading || fieldState.disabled} disabled={loading || fieldState.disabled}
error={fieldState.error} error={fieldState.error}
on:change={e => { on:change={handleChange}
fieldApi.setValue(e.detail)
}}
{processFiles} {processFiles}
{handleFileTooLarge} {handleFileTooLarge}
maximum={1} maximum={1}

View File

@ -10,9 +10,17 @@
export let validation export let validation
export let defaultValue = "" export let defaultValue = ""
export let align export let align
export let onChange
let fieldState let fieldState
let fieldApi let fieldApi
const handleChange = e => {
fieldApi.setValue(e.detail)
if (onChange) {
onChange({ value: e.detail })
}
}
</script> </script>
<Field <Field
@ -21,6 +29,7 @@
{disabled} {disabled}
{validation} {validation}
{defaultValue} {defaultValue}
{onChange}
type={type === "number" ? "number" : "string"} type={type === "number" ? "number" : "string"}
bind:fieldState bind:fieldState
bind:fieldApi bind:fieldApi
@ -29,7 +38,7 @@
<CoreTextField <CoreTextField
updateOnChange={false} updateOnChange={false}
value={fieldState.value} value={fieldState.value}
on:change={e => fieldApi.setValue(e.detail)} on:change={handleChange}
disabled={fieldState.disabled} disabled={fieldState.disabled}
error={fieldState.error} error={fieldState.error}
id={fieldState.fieldId} id={fieldState.fieldId}

View File

@ -21,6 +21,7 @@ export const UnsortableTypes = [
export const ActionTypes = { export const ActionTypes = {
ValidateForm: "ValidateForm", ValidateForm: "ValidateForm",
UpdateFieldValue: "UpdateFieldValue",
RefreshDatasource: "RefreshDatasource", RefreshDatasource: "RefreshDatasource",
AddDataProviderQueryExtension: "AddDataProviderQueryExtension", AddDataProviderQueryExtension: "AddDataProviderQueryExtension",
RemoveDataProviderQueryExtension: "RemoveDataProviderQueryExtension", RemoveDataProviderQueryExtension: "RemoveDataProviderQueryExtension",

View File

@ -162,6 +162,19 @@ const executeActionHandler = async (
} }
} }
const updateFieldValueHandler = async (action, context) => {
return await executeActionHandler(
context,
action.parameters.componentId,
ActionTypes.UpdateFieldValue,
{
type: action.parameters.type,
field: action.parameters.field,
value: action.parameters.value,
}
)
}
const validateFormHandler = async (action, context) => { const validateFormHandler = async (action, context) => {
return await executeActionHandler( return await executeActionHandler(
context, context,
@ -295,6 +308,7 @@ const handlerMap = {
["Execute Query"]: queryExecutionHandler, ["Execute Query"]: queryExecutionHandler,
["Trigger Automation"]: triggerAutomationHandler, ["Trigger Automation"]: triggerAutomationHandler,
["Validate Form"]: validateFormHandler, ["Validate Form"]: validateFormHandler,
["Update Field Value"]: updateFieldValueHandler,
["Refresh Data Provider"]: refreshDataProviderHandler, ["Refresh Data Provider"]: refreshDataProviderHandler,
["Log Out"]: logoutHandler, ["Log Out"]: logoutHandler,
["Clear Form"]: clearFormHandler, ["Clear Form"]: clearFormHandler,

View File

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

View File

@ -2,10 +2,10 @@
"author": "Budibase", "author": "Budibase",
"dependencies": { "dependencies": {
"@apidevtools/swagger-parser": "^10.0.3", "@apidevtools/swagger-parser": "^10.0.3",
"@budibase/backend-core": "^1.0.105-alpha.29", "@budibase/backend-core": "^1.0.105-alpha.30",
"@budibase/client": "^1.0.105-alpha.29", "@budibase/client": "^1.0.105-alpha.30",
"@budibase/pro": "^1.0.0", "@budibase/pro": "^1.0.0",
"@budibase/string-templates": "^1.0.105-alpha.29", "@budibase/string-templates": "^1.0.105-alpha.30",
"@bull-board/api": "^3.7.0", "@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0", "@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",
@ -148,9 +148,6 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"main": "src/index.ts", "main": "src/index.ts",
"name": "@budibase/server", "name": "@budibase/server",
"optionalDependencies": {
"oracledb": "^5.3.0"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/Budibase/budibase.git" "url": "https://github.com/Budibase/budibase.git"
@ -179,5 +176,5 @@
"test": "jest --coverage --maxWorkers=2", "test": "jest --coverage --maxWorkers=2",
"test:watch": "jest --watch" "test:watch": "jest --watch"
}, },
"version": "1.0.105-alpha.29" "version": "1.0.105-alpha.30"
} }

View File

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

View File

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