Merge pull request #6858 from Budibase/cheeks-fixes
Drag and drop fix + date filtering improvement
This commit is contained in:
commit
8e854d3e13
|
@ -9,6 +9,7 @@
|
|||
import { setContext } from "svelte"
|
||||
import DNDPositionIndicator from "./DNDPositionIndicator.svelte"
|
||||
import { DropPosition } from "./dndStore"
|
||||
import { notifications } from "@budibase/bbui"
|
||||
|
||||
let scrollRef
|
||||
|
||||
|
@ -55,6 +56,15 @@
|
|||
})
|
||||
}
|
||||
|
||||
const onDrop = async () => {
|
||||
try {
|
||||
await dndStore.actions.drop()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
notifications.error("Error saving component")
|
||||
}
|
||||
}
|
||||
|
||||
// Set scroll context so components can invoke scrolling when selected
|
||||
setContext("scroll", {
|
||||
scrollTo,
|
||||
|
@ -83,6 +93,7 @@
|
|||
opened
|
||||
scrollable
|
||||
icon="WebPage"
|
||||
on:drop={onDrop}
|
||||
>
|
||||
<ScreenslotDropdownMenu component={$selectedScreen?.props} />
|
||||
</NavItem>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import BlockComponent from "components/BlockComponent.svelte"
|
||||
import { Heading } from "@budibase/bbui"
|
||||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
import { enrichSearchColumns, enrichFilter } from "utils/blocks.js"
|
||||
|
||||
export let title
|
||||
export let dataSource
|
||||
|
@ -33,14 +34,6 @@
|
|||
const { fetchDatasourceSchema, styleable } = getContext("sdk")
|
||||
const context = getContext("context")
|
||||
const component = getContext("component")
|
||||
const schemaComponentMap = {
|
||||
string: "stringfield",
|
||||
options: "optionsfield",
|
||||
number: "numberfield",
|
||||
datetime: "datetimefield",
|
||||
boolean: "booleanfield",
|
||||
formula: "stringfield",
|
||||
}
|
||||
|
||||
let formId
|
||||
let dataProviderId
|
||||
|
@ -68,39 +61,6 @@
|
|||
},
|
||||
]
|
||||
|
||||
// Enrich the default filter with the specified search fields
|
||||
const enrichFilter = (filter, columns, formId) => {
|
||||
let enrichedFilter = [...(filter || [])]
|
||||
columns?.forEach(column => {
|
||||
const safePath = column.name.split(".").map(safe).join(".")
|
||||
enrichedFilter.push({
|
||||
field: column.name,
|
||||
operator: column.type === "string" ? "string" : "equal",
|
||||
type: column.type,
|
||||
valueType: "Binding",
|
||||
value: `{{ ${safe(formId)}.${safePath} }}`,
|
||||
})
|
||||
})
|
||||
return enrichedFilter
|
||||
}
|
||||
|
||||
// Determine data types for search fields and only use those that are valid
|
||||
const enrichSearchColumns = (searchColumns, schema) => {
|
||||
let enrichedColumns = []
|
||||
searchColumns?.forEach(column => {
|
||||
const schemaType = schema?.[column]?.type
|
||||
const componentType = schemaComponentMap[schemaType]
|
||||
if (componentType) {
|
||||
enrichedColumns.push({
|
||||
name: column,
|
||||
componentType,
|
||||
type: schemaType,
|
||||
})
|
||||
}
|
||||
})
|
||||
return enrichedColumns.slice(0, 5)
|
||||
}
|
||||
|
||||
// Builds a full details page URL for the card title
|
||||
const buildFullCardUrl = (link, url, repeaterId, linkColumn) => {
|
||||
if (!link || !url || !repeaterId) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import BlockComponent from "components/BlockComponent.svelte"
|
||||
import { Heading } from "@budibase/bbui"
|
||||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
import { enrichSearchColumns, enrichFilter } from "utils/blocks.js"
|
||||
|
||||
export let title
|
||||
export let dataSource
|
||||
|
@ -31,14 +32,6 @@
|
|||
const { fetchDatasourceSchema, styleable } = getContext("sdk")
|
||||
const context = getContext("context")
|
||||
const component = getContext("component")
|
||||
const schemaComponentMap = {
|
||||
string: "stringfield",
|
||||
options: "optionsfield",
|
||||
number: "numberfield",
|
||||
datetime: "datetimefield",
|
||||
boolean: "booleanfield",
|
||||
formula: "stringfield",
|
||||
}
|
||||
|
||||
let formId
|
||||
let dataProviderId
|
||||
|
@ -58,40 +51,6 @@
|
|||
},
|
||||
]
|
||||
|
||||
// Enrich the default filter with the specified search fields
|
||||
const enrichFilter = (filter, columns, formId) => {
|
||||
let enrichedFilter = [...(filter || [])]
|
||||
columns?.forEach(column => {
|
||||
const safePath = column.name.split(".").map(safe).join(".")
|
||||
const stringType = column.type === "string" || column.type === "formula"
|
||||
enrichedFilter.push({
|
||||
field: column.name,
|
||||
type: column.type,
|
||||
operator: stringType ? "string" : "equal",
|
||||
valueType: "Binding",
|
||||
value: `{{ ${safe(formId)}.${safePath} }}`,
|
||||
})
|
||||
})
|
||||
return enrichedFilter
|
||||
}
|
||||
|
||||
// Determine data types for search fields and only use those that are valid
|
||||
const enrichSearchColumns = (searchColumns, schema) => {
|
||||
let enrichedColumns = []
|
||||
searchColumns?.forEach(column => {
|
||||
const schemaType = schema?.[column]?.type
|
||||
const componentType = schemaComponentMap[schemaType]
|
||||
if (componentType) {
|
||||
enrichedColumns.push({
|
||||
name: column,
|
||||
componentType,
|
||||
type: schemaType,
|
||||
})
|
||||
}
|
||||
})
|
||||
return enrichedColumns.slice(0, 5)
|
||||
}
|
||||
|
||||
// Load the datasource schema so we can determine column types
|
||||
const fetchSchema = async dataSource => {
|
||||
if (dataSource) {
|
||||
|
@ -109,7 +68,7 @@
|
|||
<BlockComponent
|
||||
type="form"
|
||||
bind:id={formId}
|
||||
props={{ dataSource, disableValidation: true }}
|
||||
props={{ dataSource, disableValidation: true, editAutoColumns: true }}
|
||||
>
|
||||
{#if title || enrichedSearchColumns?.length || showTitleButton}
|
||||
<div class="header" class:mobile={$context.device.mobile}>
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
// for fields rendered in things like search blocks.
|
||||
export let disableValidation = false
|
||||
|
||||
// Not exposed as a builder setting. Used internally to allow searching on
|
||||
// auto columns.
|
||||
export let editAutoColumns = false
|
||||
|
||||
const context = getContext("context")
|
||||
const { API, fetchDatasourceSchema } = getContext("sdk")
|
||||
|
||||
|
@ -107,6 +111,7 @@
|
|||
{table}
|
||||
{initialValues}
|
||||
{disableValidation}
|
||||
{editAutoColumns}
|
||||
>
|
||||
<slot />
|
||||
</InnerForm>
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
export let schema
|
||||
export let table
|
||||
export let disableValidation = false
|
||||
export let editAutoColumns = false
|
||||
|
||||
const component = getContext("component")
|
||||
const { styleable, Provider, ActionTypes } = getContext("sdk")
|
||||
|
@ -183,7 +184,8 @@
|
|||
fieldId,
|
||||
value: initialValue,
|
||||
error: initialError,
|
||||
disabled: disabled || fieldDisabled || isAutoColumn,
|
||||
disabled:
|
||||
disabled || fieldDisabled || (isAutoColumn && !editAutoColumns),
|
||||
defaultValue,
|
||||
validator,
|
||||
lastUpdate: Date.now(),
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import { makePropSafe as safe } from "@budibase/string-templates"
|
||||
|
||||
// Map of data types to component types for search fields inside blocks
|
||||
const schemaComponentMap = {
|
||||
string: "stringfield",
|
||||
options: "optionsfield",
|
||||
number: "numberfield",
|
||||
datetime: "datetimefield",
|
||||
boolean: "booleanfield",
|
||||
formula: "stringfield",
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine data types for search fields and only use those that are valid
|
||||
* @param searchColumns the search columns to use
|
||||
* @param schema the data source schema
|
||||
*/
|
||||
export const enrichSearchColumns = (searchColumns, schema) => {
|
||||
let enrichedColumns = []
|
||||
searchColumns?.forEach(column => {
|
||||
const schemaType = schema?.[column]?.type
|
||||
const componentType = schemaComponentMap[schemaType]
|
||||
if (componentType) {
|
||||
enrichedColumns.push({
|
||||
name: column,
|
||||
componentType,
|
||||
type: schemaType,
|
||||
})
|
||||
}
|
||||
})
|
||||
return enrichedColumns.slice(0, 5)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enriches a normal datasource filter with bindings representing the additional
|
||||
* search fields configured as part of a searchable block. These bindings are
|
||||
* fields inside a form used as part of the block.
|
||||
* @param filter the normal data provider filter
|
||||
* @param columns the enriched search column structure
|
||||
* @param formId the ID of the form containing the search fields
|
||||
*/
|
||||
export const enrichFilter = (filter, columns, formId) => {
|
||||
let enrichedFilter = [...(filter || [])]
|
||||
columns?.forEach(column => {
|
||||
const safePath = column.name.split(".").map(safe).join(".")
|
||||
const stringType = column.type === "string" || column.type === "formula"
|
||||
const dateType = column.type === "datetime"
|
||||
const binding = `${safe(formId)}.${safePath}`
|
||||
|
||||
// For dates, use a range of the entire day selected
|
||||
if (dateType) {
|
||||
enrichedFilter.push({
|
||||
field: column.name,
|
||||
type: column.type,
|
||||
operator: "rangeLow",
|
||||
valueType: "Binding",
|
||||
value: `{{ ${binding} }}`,
|
||||
})
|
||||
const format = "YYYY-MM-DDTHH:mm:ss.SSSZ"
|
||||
enrichedFilter.push({
|
||||
field: column.name,
|
||||
type: column.type,
|
||||
operator: "rangeHigh",
|
||||
valueType: "Binding",
|
||||
value: `{{ date (add (date ${binding} "x") 86399999) "${format}" }}`,
|
||||
})
|
||||
}
|
||||
|
||||
// For other fields, do an exact match
|
||||
else {
|
||||
enrichedFilter.push({
|
||||
field: column.name,
|
||||
type: column.type,
|
||||
operator: stringType ? "string" : "equal",
|
||||
valueType: "Binding",
|
||||
value: `{{ ${binding} }}`,
|
||||
})
|
||||
}
|
||||
})
|
||||
return enrichedFilter
|
||||
}
|
|
@ -99,8 +99,16 @@ export const buildLuceneQuery = filter => {
|
|||
filter.forEach(expression => {
|
||||
let { operator, field, type, value, externalType } = expression
|
||||
// Parse all values into correct types
|
||||
if (type === "datetime" && value) {
|
||||
value = new Date(value).toISOString()
|
||||
if (type === "datetime") {
|
||||
// Ensure date value is a valid date and parse into correct format
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
value = new Date(value).toISOString()
|
||||
} catch (error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (type === "number" && !Array.isArray(value)) {
|
||||
if (operator === "oneOf") {
|
||||
|
|
Loading…
Reference in New Issue