More fixes (#9387)

* Mark filters as nested settings to support persisting bindings post block ejection

* Add support for searching on linked fields in blocks

* Fix multi-select pickers closing on every click

* Target spectrum root element by default when rendering popovers, and allow customisation via context for client library

* Don't send up invalid HBS expressions when filtering on dates in blocks with empty date value

* Move profile above theme in user dropdown
This commit is contained in:
Andrew Kingston 2023-01-19 16:09:40 +00:00 committed by GitHub
parent d5aebb3db4
commit 2a2466fbda
9 changed files with 62 additions and 19 deletions

View File

@ -45,7 +45,9 @@
getOptionLabel getOptionLabel
) )
const onClick = () => { const onClick = e => {
e.preventDefault()
e.stopPropagation()
dispatch("click") dispatch("click")
if (readonly) { if (readonly) {
return return
@ -88,7 +90,6 @@
class:is-open={open} class:is-open={open}
aria-haspopup="listbox" aria-haspopup="listbox"
on:click={onClick} on:click={onClick}
use:clickOutside={() => (open = false)}
bind:this={button} bind:this={button}
> >
{#if fieldIcon} {#if fieldIcon}
@ -130,14 +131,17 @@
<Popover <Popover
anchor={button} anchor={button}
align="left" align="left"
portalTarget={document.documentElement}
bind:this={popover} bind:this={popover}
{open} {open}
on:close={() => (open = false)} on:close={() => (open = false)}
useAnchorWidth={!autoWidth} useAnchorWidth={!autoWidth}
maxWidth={autoWidth ? 400 : null} maxWidth={autoWidth ? 400 : null}
> >
<div class="popover-content" class:auto-width={autoWidth}> <div
class="popover-content"
class:auto-width={autoWidth}
use:clickOutside={() => (open = false)}
>
{#if autocomplete} {#if autocomplete}
<Search <Search
value={searchTerm} value={searchTerm}

View File

@ -5,6 +5,8 @@
import positionDropdown from "../Actions/position_dropdown" import positionDropdown from "../Actions/position_dropdown"
import clickOutside from "../Actions/click_outside" import clickOutside from "../Actions/click_outside"
import { fly } from "svelte/transition" import { fly } from "svelte/transition"
import { getContext } from "svelte"
import Context from "../context"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -24,6 +26,7 @@
$: tooltipClasses = showTip $: tooltipClasses = showTip
? `spectrum-Popover--withTip spectrum-Popover--${direction}` ? `spectrum-Popover--withTip spectrum-Popover--${direction}`
: "" : ""
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
export const show = () => { export const show = () => {
dispatch("open") dispatch("open")
@ -61,7 +64,7 @@
</script> </script>
{#if open} {#if open}
<Portal target={portalTarget}> <Portal {target}>
<div <div
tabindex="0" tabindex="0"
use:positionDropdown={{ anchor, align, maxWidth, useAnchorWidth }} use:positionDropdown={{ anchor, align, maxWidth, useAnchorWidth }}

View File

@ -1,3 +1,4 @@
export default { export default {
Modal: "bbui-modal", Modal: "bbui-modal",
PopoverRoot: "bbui-popover-root",
} }

View File

@ -26,9 +26,6 @@
<Avatar size="M" initials={$auth.initials} url={$auth.user.pictureUrl} /> <Avatar size="M" initials={$auth.initials} url={$auth.user.pictureUrl} />
<Icon size="XL" name="ChevronDown" /> <Icon size="XL" name="ChevronDown" />
</div> </div>
<MenuItem icon="Moon" on:click={() => themeModal.show()} dataCy="theme">
Theme
</MenuItem>
<MenuItem <MenuItem
icon="UserEdit" icon="UserEdit"
on:click={() => profileModal.show()} on:click={() => profileModal.show()}
@ -36,6 +33,9 @@
> >
My profile My profile
</MenuItem> </MenuItem>
<MenuItem icon="Moon" on:click={() => themeModal.show()} dataCy="theme">
Theme
</MenuItem>
<MenuItem icon="LockClosed" on:click={() => updatePasswordModal.show()}> <MenuItem icon="LockClosed" on:click={() => updatePasswordModal.show()}>
Update password Update password
</MenuItem> </MenuItem>

View File

@ -4019,7 +4019,8 @@
{ {
"type": "filter", "type": "filter",
"label": "Filtering", "label": "Filtering",
"key": "filter" "key": "filter",
"nested": true
}, },
{ {
"type": "field", "type": "field",
@ -4535,7 +4536,8 @@
{ {
"type": "filter", "type": "filter",
"label": "Filtering", "label": "Filtering",
"key": "filter" "key": "filter",
"nested": true
}, },
{ {
"type": "searchfield", "type": "searchfield",
@ -4665,7 +4667,8 @@
{ {
"type": "filter", "type": "filter",
"label": "Filtering", "label": "Filtering",
"key": "filter" "key": "filter",
"nested": true
}, },
{ {
"type": "field/sortable", "type": "field/sortable",
@ -4831,7 +4834,8 @@
{ {
"type": "filter", "type": "filter",
"label": "Filtering", "label": "Filtering",
"key": "filter" "key": "filter",
"nested": true
}, },
{ {
"type": "field/sortable", "type": "field/sortable",

View File

@ -1,5 +1,9 @@
<script> <script>
import { themeStore } from "stores" import { themeStore } from "stores"
import { setContext } from "svelte"
import { Context } from "@budibase/bbui"
setContext(Context.PopoverRoot, "#theme-root")
</script> </script>
<div style={$themeStore.customThemeCss} id="theme-root"> <div style={$themeStore.customThemeCss} id="theme-root">

View File

@ -36,9 +36,12 @@
let dataProviderId let dataProviderId
let repeaterId let repeaterId
let schema let schema
let enrichedSearchColumns
$: fetchSchema(dataSource) $: fetchSchema(dataSource)
$: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema) $: enrichSearchColumns(searchColumns, schema).then(
val => (enrichedSearchColumns = val)
)
$: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId)
$: cardWidth = cardHorizontal ? 420 : 300 $: cardWidth = cardHorizontal ? 420 : 300
$: fullCardURL = buildFullCardUrl( $: fullCardURL = buildFullCardUrl(

View File

@ -36,9 +36,12 @@
let newRowSidePanelId let newRowSidePanelId
let schema let schema
let primaryDisplay let primaryDisplay
let enrichedSearchColumns
$: fetchSchema(dataSource) $: fetchSchema(dataSource)
$: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema) $: enrichSearchColumns(searchColumns, schema).then(
val => (enrichedSearchColumns = val)
)
$: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId)
$: editTitle = getEditTitle(detailsFormBlockId, primaryDisplay) $: editTitle = getEditTitle(detailsFormBlockId, primaryDisplay)
$: normalFields = getNormalFields(schema) $: normalFields = getNormalFields(schema)

View File

@ -1,4 +1,5 @@
import { makePropSafe as safe } from "@budibase/string-templates" import { makePropSafe as safe } from "@budibase/string-templates"
import { API } from "../api/index.js"
// Map of data types to component types for search fields inside blocks // Map of data types to component types for search fields inside blocks
const schemaComponentMap = { const schemaComponentMap = {
@ -15,10 +16,28 @@ const schemaComponentMap = {
* @param searchColumns the search columns to use * @param searchColumns the search columns to use
* @param schema the datasource schema * @param schema the datasource schema
*/ */
export const enrichSearchColumns = (searchColumns, schema) => { export const enrichSearchColumns = async (searchColumns, schema) => {
if (!searchColumns?.length || !schema) {
return []
}
let enrichedColumns = [] let enrichedColumns = []
searchColumns?.forEach(column => { for (let column of searchColumns) {
const schemaType = schema?.[column]?.type let schemaType = schema[column]?.type
// Check if this is a field in another related table. The only way we can
// check this is checking for a "." inside the column, then checking if we
// have a link field named the same as that field prefix.
if (column.includes(".")) {
const split = column.split(".")
const sourceField = split[0]
const linkField = split.slice(1).join(".")
const linkSchema = schema[sourceField]
if (linkSchema?.type === "link") {
const linkedDef = await API.fetchTableDefinition(linkSchema.tableId)
schemaType = linkedDef?.schema?.[linkField]?.type
}
}
const componentType = schemaComponentMap[schemaType] const componentType = schemaComponentMap[schemaType]
if (componentType) { if (componentType) {
enrichedColumns.push({ enrichedColumns.push({
@ -27,7 +46,7 @@ export const enrichSearchColumns = (searchColumns, schema) => {
type: schemaType, type: schemaType,
}) })
} }
}) }
return enrichedColumns.slice(0, 5) return enrichedColumns.slice(0, 5)
} }
@ -57,12 +76,14 @@ export const enrichFilter = (filter, columns, formId) => {
value: `{{ ${binding} }}`, value: `{{ ${binding} }}`,
}) })
const format = "YYYY-MM-DDTHH:mm:ss.SSSZ" const format = "YYYY-MM-DDTHH:mm:ss.SSSZ"
let hbs = `{{ date (add (date ${binding} "x") 86399999) "${format}" }}`
hbs = `{{#if ${binding} }}${hbs}{{/if}}`
enrichedFilter.push({ enrichedFilter.push({
field: column.name, field: column.name,
type: column.type, type: column.type,
operator: "rangeHigh", operator: "rangeHigh",
valueType: "Binding", valueType: "Binding",
value: `{{ date (add (date ${binding} "x") 86399999) "${format}" }}`, value: hbs,
}) })
} }