Add working side panels to table blocks

This commit is contained in:
Andrew Kingston 2022-11-17 10:16:45 +00:00
parent 43fb581fde
commit e8b993b14c
8 changed files with 242 additions and 122 deletions

View File

@ -25,7 +25,7 @@ const generateTableBlock = table => {
linkURL: `${rowListUrl(table)}/:id`, linkURL: `${rowListUrl(table)}/:id`,
showAutoColumns: false, showAutoColumns: false,
showTitleButton: true, showTitleButton: true,
titleButtonText: "Create new", titleButtonText: "Create row",
titleButtonURL: newRowUrl(table), titleButtonURL: newRowUrl(table),
title: table.name, title: table.name,
dataSource: { dataSource: {

View File

@ -1,4 +1,4 @@
import { Checkbox, Select, Stepper } from "@budibase/bbui" import { Checkbox, Select, RadioGroup, Stepper } from "@budibase/bbui"
import DataSourceSelect from "./controls/DataSourceSelect.svelte" import DataSourceSelect from "./controls/DataSourceSelect.svelte"
import S3DataSourceSelect from "./controls/S3DataSourceSelect.svelte" import S3DataSourceSelect from "./controls/S3DataSourceSelect.svelte"
import DataProviderSelect from "./controls/DataProviderSelect.svelte" import DataProviderSelect from "./controls/DataProviderSelect.svelte"
@ -24,6 +24,7 @@ import BarButtonList from "./controls/BarButtonList.svelte"
const componentMap = { const componentMap = {
text: DrawerBindableCombobox, text: DrawerBindableCombobox,
select: Select, select: Select,
radio: RadioGroup,
dataSource: DataSourceSelect, dataSource: DataSourceSelect,
"dataSource/s3": S3DataSourceSelect, "dataSource/s3": S3DataSourceSelect,
dataProvider: DataProviderSelect, dataProvider: DataProviderSelect,

View File

@ -36,7 +36,9 @@
section.settings.forEach(setting => { section.settings.forEach(setting => {
setting.visible = canRenderControl(instance, setting, isScreen) setting.visible = canRenderControl(instance, setting, isScreen)
}) })
section.visible = section.settings.some(setting => setting.visible) section.visible =
section.name === "General" ||
section.settings.some(setting => setting.visible)
}) })
return sections return sections

View File

@ -3733,12 +3733,6 @@
"key": "dataProvider", "key": "dataProvider",
"required": true "required": true
}, },
{
"type": "number",
"label": "Row count",
"key": "rowCount",
"defaultValue": 8
},
{ {
"type": "columns", "type": "columns",
"label": "Columns", "label": "Columns",
@ -3762,6 +3756,12 @@
} }
] ]
}, },
{
"type": "number",
"label": "Row count",
"key": "rowCount",
"defaultValue": 8
},
{ {
"type": "boolean", "type": "boolean",
"label": "Quiet", "label": "Quiet",
@ -3772,12 +3772,6 @@
"label": "Compact", "label": "Compact",
"key": "compact" "key": "compact"
}, },
{
"type": "boolean",
"label": "Show auto columns",
"key": "showAutoColumns",
"defaultValue": false
},
{ {
"type": "boolean", "type": "boolean",
"label": "Allow row selection", "label": "Allow row selection",
@ -3785,14 +3779,20 @@
"defaultValue": false, "defaultValue": false,
"info": "Row selection is only compatible with internal or SQL tables" "info": "Row selection is only compatible with internal or SQL tables"
}, },
{ {
"type": "event", "section": true,
"label": "On row click", "name": "On Row Click",
"key": "onClick", "settings": [
"context": [
{ {
"label": "Clicked row", "type": "event",
"key": "row" "key": "onClick",
"context": [
{
"label": "Clicked row",
"key": "row"
}
]
} }
] ]
} }
@ -4445,70 +4445,15 @@
"label": "Title", "label": "Title",
"key": "title" "key": "title"
}, },
{
"type": "dataSource",
"label": "Data",
"key": "dataSource",
"required": true
},
{
"type": "searchfield",
"label": "Search Columns",
"key": "searchColumns",
"placeholder": "Choose search columns",
"info": "Only the first 5 search columns will be used"
},
{
"type": "filter",
"label": "Filtering",
"key": "filter"
},
{
"type": "field/sortable",
"label": "Sort Column",
"key": "sortColumn"
},
{
"type": "select",
"label": "Sort Order",
"key": "sortOrder",
"options": [
"Ascending",
"Descending"
],
"defaultValue": "Descending"
},
{
"type": "select",
"label": "Size",
"key": "size",
"defaultValue": "spectrum--medium",
"options": [
{
"label": "Medium",
"value": "spectrum--medium"
},
{
"label": "Large",
"value": "spectrum--large"
}
]
},
{
"type": "boolean",
"label": "Paginate",
"key": "paginate",
"defaultValue": true
},
{ {
"section": true, "section": true,
"name": "Table", "name": "Table",
"settings": [ "settings": [
{ {
"type": "number", "type": "dataSource",
"label": "Scroll Limit", "label": "Data",
"key": "rowCount", "key": "dataSource",
"defaultValue": 8 "required": true
}, },
{ {
"type": "columns", "type": "columns",
@ -4518,9 +4463,52 @@
"placeholder": "All columns", "placeholder": "All columns",
"nested": true "nested": true
}, },
{
"type": "field/sortable",
"label": "Sort By",
"key": "sortColumn"
},
{
"type": "select",
"label": "Sort Order",
"key": "sortOrder",
"options": [
"Ascending",
"Descending"
],
"defaultValue": "Descending"
},
{
"type": "select",
"label": "Size",
"key": "size",
"defaultValue": "spectrum--medium",
"options": [
{
"label": "Medium",
"value": "spectrum--medium"
},
{
"label": "Large",
"value": "spectrum--large"
}
]
},
{
"type": "number",
"label": "Scroll Limit",
"key": "rowCount",
"defaultValue": 8
},
{ {
"type": "boolean", "type": "boolean",
"label": "Quiet table variant", "label": "Paginate",
"key": "paginate",
"defaultValue": true
},
{
"type": "boolean",
"label": "Quiet",
"key": "quiet" "key": "quiet"
}, },
{ {
@ -4528,21 +4516,53 @@
"label": "Compact", "label": "Compact",
"key": "compact" "key": "compact"
}, },
{
"type": "boolean",
"label": "Show auto columns",
"key": "showAutoColumns"
},
{ {
"type": "boolean", "type": "boolean",
"label": "Allow row selection", "label": "Allow row selection",
"key": "allowSelectRows", "key": "allowSelectRows",
"info": "Row selection is only compatible with internal or SQL tables" "info": "Row selection is only compatible with internal or SQL tables"
}, },
{
"type": "filter",
"label": "Filtering",
"key": "filter"
},
{
"type": "searchfield",
"label": "Search Fields",
"key": "searchColumns",
"placeholder": "Choose search fields",
"info": "Only the first 5 search fields will be used"
}
]
},
{
"section": true,
"name": "On row click",
"settings": [
{
"type": "radio",
"key": "clickBehaviour",
"defaultValue": "details",
"options": [
{
"label": "Show details side panel",
"value": "details"
},
{
"label": "Run actions",
"value": "actions"
}
]
},
{ {
"type": "event", "type": "event",
"label": "On row click",
"key": "onClick", "key": "onClick",
"nested": true,
"dependsOn": {
"setting": "clickBehaviour",
"value": "actions"
},
"context": [{ "context": [{
"label": "Clicked row", "label": "Clicked row",
"key": "row" "key": "row"
@ -4552,28 +4572,46 @@
}, },
{ {
"section": true, "section": true,
"name": "Title button", "name": "Button",
"settings": [ "settings": [
{ {
"type": "boolean", "type": "boolean",
"key": "showTitleButton", "key": "showTitleButton",
"label": "Show link button", "label": "Show button above table",
"defaultValue": false "defaultValue": true
},
{
"type": "boolean",
"label": "Open link in modal",
"key": "titleButtonPeek"
}, },
{ {
"type": "text", "type": "text",
"key": "titleButtonText", "key": "titleButtonText",
"label": "Button text" "label": "Text",
"defaultValue": "Create row",
"dependsOn": "showTitleButton"
}, },
{ {
"type": "url", "type": "radio",
"label": "Button link", "key": "titleButtonClickBehaviour",
"key": "titleButtonURL" "label": "On Click",
"dependsOn": "showTitleButton",
"defaultValue": "new",
"options": [
{
"label": "Show new row side panel",
"value": "new"
},
{
"label": "Run actions",
"value": "actions"
}
]
},
{
"type": "event",
"key": "onClickTitleButton",
"nested": true,
"dependsOn": {
"setting": "titleButtonClickBehaviour",
"value": "actions"
}
} }
] ]
} }

View File

@ -1,5 +1,5 @@
<script> <script>
import { getContext } from "svelte" import { getContext, onMount } from "svelte"
const component = getContext("component") const component = getContext("component")
const { styleable, sidePanelStore, builderStore } = getContext("sdk") const { styleable, sidePanelStore, builderStore } = getContext("sdk")
@ -15,11 +15,9 @@
} }
const update = visible => { const update = visible => {
if (visible) { if (visible) {
sidePanelStore.actions.open($component.id)
target.appendChild(el) target.appendChild(el)
el.hidden = false el.hidden = false
} else { } else {
sidePanelStore.actions.close()
destroy() destroy()
el.hidden = true el.hidden = true
} }
@ -41,7 +39,9 @@
hidden hidden
class="side-panel" class="side-panel"
> >
<slot /> {#if open}
<slot />
{/if}
</div> </div>
<style> <style>

View File

@ -13,37 +13,68 @@
export let sortOrder export let sortOrder
export let paginate export let paginate
export let tableColumns export let tableColumns
export let showAutoColumns
export let rowCount export let rowCount
export let quiet export let quiet
export let compact export let compact
export let size export let size
export let allowSelectRows export let allowSelectRows
export let clickBehaviour
export let onClick export let onClick
export let showTitleButton export let showTitleButton
export let titleButtonText export let titleButtonText
export let titleButtonURL export let titleButtonClickBehaviour
export let titleButtonPeek export let onClickTitleButton
const { fetchDatasourceSchema } = getContext("sdk") const { fetchDatasourceSchema } = getContext("sdk")
const stateKey = `${Math.random()}-id`
let formId let formId
let dataProviderId let dataProviderId
let detailsSidePanelId
let newRowSidePanelId
let schema let schema
let schemaLoaded = false let schemaLoaded = false
$: fetchSchema(dataSource) $: fetchSchema(dataSource)
$: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema) $: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema)
$: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId)
$: titleButtonAction = [ $: normalFields = getNormalFields(schema)
{ $: rowClickActions =
"##eventHandlerType": "Navigate To", clickBehaviour === "actions"
parameters: { ? onClick
peek: titleButtonPeek, : [
url: titleButtonURL, {
}, id: 0,
}, "##eventHandlerType": "Update State",
] parameters: {
key: stateKey,
type: "set",
persist: false,
value: `{{ ${safe("eventContext")}.${safe("row")}.${safe(
"_id"
)} }}`,
},
},
{
id: 1,
"##eventHandlerType": "Open Side Panel",
parameters: {
id: detailsSidePanelId,
},
},
]
$: buttonClickActions =
titleButtonClickBehaviour === "actions"
? onClickTitleButton
: [
{
id: 0,
"##eventHandlerType": "Open Side Panel",
parameters: {
id: newRowSidePanelId,
},
},
]
// Load the datasource schema so we can determine column types // Load the datasource schema so we can determine column types
const fetchSchema = async dataSource => { const fetchSchema = async dataSource => {
@ -54,6 +85,17 @@
} }
schemaLoaded = true schemaLoaded = true
} }
const getNormalFields = schema => {
if (!schema) {
return []
}
return Object.entries(schema)
.filter(entry => {
return !entry[1].autocolumn
})
.map(entry => entry[0])
}
</script> </script>
{#if schemaLoaded} {#if schemaLoaded}
@ -126,7 +168,7 @@
<BlockComponent <BlockComponent
type="button" type="button"
props={{ props={{
onClick: titleButtonAction, onClick: buttonClickActions,
text: titleButtonText, text: titleButtonText,
type: "cta", type: "cta",
}} }}
@ -142,7 +184,7 @@
props={{ props={{
dataSource, dataSource,
filter: enrichedFilter, filter: enrichedFilter,
sortColumn, sortColumn: sortColumn || normalFields?.[0],
sortOrder, sortOrder,
paginate, paginate,
limit: rowCount, limit: rowCount,
@ -155,13 +197,51 @@
props={{ props={{
dataProvider: `{{ literal ${safe(dataProviderId)} }}`, dataProvider: `{{ literal ${safe(dataProviderId)} }}`,
columns: tableColumns, columns: tableColumns,
showAutoColumns,
rowCount, rowCount,
quiet, quiet,
compact, compact,
allowSelectRows, allowSelectRows,
size, size,
onClick, onClick: rowClickActions,
}}
/>
</BlockComponent>
<BlockComponent
type="sidepanel"
bind:id={detailsSidePanelId}
context="details-side-panel"
order={2}
>
<BlockComponent
type="formblock"
props={{
dataSource,
showSaveButton: true,
showDeleteButton: true,
actionType: "Update",
rowId: `{{ ${safe("state")}.${safe(stateKey)} }}`,
fields: normalFields,
title: "Row Details",
labelPosition: "left",
}}
/>
</BlockComponent>
<BlockComponent
type="sidepanel"
bind:id={newRowSidePanelId}
context="new-side-panel"
order={3}
>
<BlockComponent
type="formblock"
props={{
dataSource,
showSaveButton: true,
showDeleteButton: false,
actionType: "Create",
fields: normalFields,
title: "Create Row",
labelPosition: "left",
}} }}
/> />
</BlockComponent> </BlockComponent>

View File

@ -66,7 +66,7 @@
$: initialValues = getInitialValues(actionType, dataSource, $context) $: initialValues = getInitialValues(actionType, dataSource, $context)
$: resetKey = Helpers.hashString( $: resetKey = Helpers.hashString(
JSON.stringify(initialValues) + JSON.stringify(schema) + disabled JSON.stringify(initialValues) + JSON.stringify(dataSource) + disabled
) )
</script> </script>

View File

@ -7,7 +7,6 @@
export let dataProvider export let dataProvider
export let columns export let columns
export let showAutoColumns
export let rowCount export let rowCount
export let quiet export let quiet
export let size export let size
@ -32,7 +31,7 @@
$: loading = dataProvider?.loading ?? false $: loading = dataProvider?.loading ?? false
$: data = dataProvider?.rows || [] $: data = dataProvider?.rows || []
$: fullSchema = dataProvider?.schema ?? {} $: fullSchema = dataProvider?.schema ?? {}
$: fields = getFields(fullSchema, columns, showAutoColumns) $: fields = getFields(fullSchema, columns, false)
$: schema = getFilteredSchema(fullSchema, fields, hasChildren) $: schema = getFilteredSchema(fullSchema, fields, hasChildren)
$: setSorting = getAction( $: setSorting = getAction(
dataProvider?.id, dataProvider?.id,