Merge pull request #15353 from Budibase/ts/client-utils

Type client utils
This commit is contained in:
Adria Navarro 2025-01-13 17:16:43 +01:00 committed by GitHub
commit 322810ae66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 71 additions and 22 deletions

View File

@ -39,7 +39,7 @@
getActionContextKey, getActionContextKey,
getActionDependentContextKeys, getActionDependentContextKeys,
} from "../utils/buttonActions.js" } from "../utils/buttonActions.js"
import { gridLayout } from "utils/grid.js" import { gridLayout } from "utils/grid"
export let instance = {} export let instance = {}
export let parent = null export let parent = null

View File

@ -74,6 +74,7 @@ export default {
fetchData, fetchData,
QueryUtils, QueryUtils,
ContextScopes: Constants.ContextScopes, ContextScopes: Constants.ContextScopes,
// This is not used internally but exposed to users to be used in plugins
getAPIKey, getAPIKey,
enrichButtonActions, enrichButtonActions,
processStringSync, processStringSync,

View File

@ -1,10 +1,16 @@
import { makePropSafe as safe } from "@budibase/string-templates" import { makePropSafe as safe } from "@budibase/string-templates"
import { API } from "../api" import { API } from "../api"
import { UILogicalOperator } from "@budibase/types" import {
BasicOperator,
LegacyFilter,
UIColumn,
UILogicalOperator,
UISearchFilter,
} from "@budibase/types"
import { Constants } from "@budibase/frontend-core" import { Constants } from "@budibase/frontend-core"
// 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: Record<string, string> = {
string: "stringfield", string: "stringfield",
options: "optionsfield", options: "optionsfield",
number: "numberfield", number: "numberfield",
@ -19,7 +25,16 @@ 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 = async (searchColumns, schema) => { export const enrichSearchColumns = async (
searchColumns: string[],
schema: Record<
string,
{
tableId: string
type: string
}
>
) => {
if (!searchColumns?.length || !schema) { if (!searchColumns?.length || !schema) {
return [] return []
} }
@ -61,12 +76,16 @@ export const enrichSearchColumns = async (searchColumns, schema) => {
* @param columns the enriched search column structure * @param columns the enriched search column structure
* @param formId the ID of the form containing the search fields * @param formId the ID of the form containing the search fields
*/ */
export const enrichFilter = (filter, columns, formId) => { export const enrichFilter = (
filter: UISearchFilter,
columns: UIColumn[],
formId: string
) => {
if (!columns?.length) { if (!columns?.length) {
return filter return filter
} }
let newFilters = [] const newFilters: LegacyFilter[] = []
columns?.forEach(column => { columns?.forEach(column => {
const safePath = column.name.split(".").map(safe).join(".") const safePath = column.name.split(".").map(safe).join(".")
const stringType = column.type === "string" || column.type === "formula" const stringType = column.type === "string" || column.type === "formula"
@ -99,7 +118,7 @@ export const enrichFilter = (filter, columns, formId) => {
newFilters.push({ newFilters.push({
field: column.name, field: column.name,
type: column.type, type: column.type,
operator: stringType ? "string" : "equal", operator: stringType ? BasicOperator.STRING : BasicOperator.EQUAL,
valueType: "Binding", valueType: "Binding",
value: `{{ ${binding} }}`, value: `{{ ${binding} }}`,
}) })

View File

@ -1,7 +1,27 @@
import { GridSpacing, GridRowHeight } from "constants" import { GridSpacing, GridRowHeight } from "@/constants"
import { builderStore } from "stores" import { builderStore } from "stores"
import { buildStyleString } from "utils/styleable.js" import { buildStyleString } from "utils/styleable.js"
interface GridMetadata {
id: string
styles: Record<string, string | number> & {
"--default-width"?: number
"--default-height"?: number
}
interactive: boolean
errored: boolean
definition?: {
size?: {
width: number
height: number
}
grid?: { hAlign: string; vAlign: string }
}
draggable: boolean
insideGrid: boolean
ignoresLayout: boolean
}
/** /**
* We use CSS variables on components to control positioning and layout of * We use CSS variables on components to control positioning and layout of
* components inside grids. * components inside grids.
@ -44,14 +64,17 @@ export const GridDragModes = {
} }
// Builds a CSS variable name for a certain piece of grid metadata // Builds a CSS variable name for a certain piece of grid metadata
export const getGridVar = (device, param) => `--grid-${device}-${param}` export const getGridVar = (device: string, param: string) =>
`--grid-${device}-${param}`
// Determines whether a JS event originated from immediately within a grid // Determines whether a JS event originated from immediately within a grid
export const isGridEvent = e => { export const isGridEvent = (e: Event & { target: HTMLElement }): boolean => {
return ( return (
e.target.dataset?.indicator === "true" || e.target.dataset?.indicator === "true" ||
// @ts-expect-error: api is not properly typed
e.target e.target
.closest?.(".component") .closest?.(".component")
// @ts-expect-error
?.parentNode.closest(".component") ?.parentNode.closest(".component")
?.childNodes[0]?.classList?.contains("grid") ?.childNodes[0]?.classList?.contains("grid")
) )
@ -59,11 +82,11 @@ export const isGridEvent = e => {
// Svelte action to apply required class names and styles to our component // Svelte action to apply required class names and styles to our component
// wrappers // wrappers
export const gridLayout = (node, metadata) => { export const gridLayout = (node: HTMLDivElement, metadata: GridMetadata) => {
let selectComponent let selectComponent: ((e: Event) => void) | null
// Applies the required listeners, CSS and classes to a component DOM node // Applies the required listeners, CSS and classes to a component DOM node
const applyMetadata = metadata => { const applyMetadata = (metadata: GridMetadata) => {
const { const {
id, id,
styles, styles,
@ -86,7 +109,7 @@ export const gridLayout = (node, metadata) => {
} }
// Callback to select the component when clicking on the wrapper // Callback to select the component when clicking on the wrapper
selectComponent = e => { selectComponent = (e: Event) => {
e.stopPropagation() e.stopPropagation()
builderStore.actions.selectComponent(id) builderStore.actions.selectComponent(id)
} }
@ -100,7 +123,7 @@ export const gridLayout = (node, metadata) => {
} }
width += 2 * GridSpacing width += 2 * GridSpacing
height += 2 * GridSpacing height += 2 * GridSpacing
let vars = { const vars: Record<string, string | number> = {
"--default-width": width, "--default-width": width,
"--default-height": height, "--default-height": height,
} }
@ -135,7 +158,7 @@ export const gridLayout = (node, metadata) => {
} }
// Apply some metadata to data attributes to speed up lookups // Apply some metadata to data attributes to speed up lookups
const addDataTag = (tagName, device, param) => { const addDataTag = (tagName: string, device: string, param: string) => {
const val = `${vars[getGridVar(device, param)]}` const val = `${vars[getGridVar(device, param)]}`
if (node.dataset[tagName] !== val) { if (node.dataset[tagName] !== val) {
node.dataset[tagName] = val node.dataset[tagName] = val
@ -147,11 +170,12 @@ export const gridLayout = (node, metadata) => {
addDataTag("gridMobileHAlign", Devices.Mobile, GridParams.HAlign) addDataTag("gridMobileHAlign", Devices.Mobile, GridParams.HAlign)
addDataTag("gridDesktopVAlign", Devices.Desktop, GridParams.VAlign) addDataTag("gridDesktopVAlign", Devices.Desktop, GridParams.VAlign)
addDataTag("gridMobileVAlign", Devices.Mobile, GridParams.VAlign) addDataTag("gridMobileVAlign", Devices.Mobile, GridParams.VAlign)
if (node.dataset.insideGrid !== true) { if (node.dataset.insideGrid !== "true") {
node.dataset.insideGrid = true node.dataset.insideGrid = "true"
} }
// Apply all CSS variables to the wrapper // Apply all CSS variables to the wrapper
// @ts-expect-error TODO
node.style = buildStyleString(vars) node.style = buildStyleString(vars)
// Add a listener to select this node on click // Add a listener to select this node on click
@ -160,7 +184,7 @@ export const gridLayout = (node, metadata) => {
} }
// Add draggable attribute // Add draggable attribute
node.setAttribute("draggable", !!draggable) node.setAttribute("draggable", (!!draggable).toString())
} }
// Removes the previously set up listeners // Removes the previously set up listeners
@ -176,7 +200,7 @@ export const gridLayout = (node, metadata) => {
applyMetadata(metadata) applyMetadata(metadata)
return { return {
update(newMetadata) { update(newMetadata: GridMetadata) {
removeListeners() removeListeners()
applyMetadata(newMetadata) applyMetadata(newMetadata)
}, },

View File

@ -1,8 +1,8 @@
import { get } from "svelte/store" import { get } from "svelte/store"
import { link } from "svelte-spa-router" import { link, LinkActionOpts } from "svelte-spa-router"
import { builderStore } from "stores" import { builderStore } from "stores"
export const linkable = (node, href) => { export const linkable = (node: HTMLElement, href?: LinkActionOpts) => {
if (get(builderStore).inBuilder) { if (get(builderStore).inBuilder) {
node.onclick = e => { node.onclick = e => {
e.preventDefault() e.preventDefault()

View File

@ -14,6 +14,7 @@
"../*", "../*",
"../../node_modules/@budibase/*" "../../node_modules/@budibase/*"
], ],
"@/*": ["./src/*"],
"*": ["./src/*"] "*": ["./src/*"]
} }
} }

View File

@ -67,6 +67,10 @@ export default defineConfig(({ mode }) => {
find: "constants", find: "constants",
replacement: path.resolve("./src/constants"), replacement: path.resolve("./src/constants"),
}, },
{
find: "@/constants",
replacement: path.resolve("./src/constants"),
},
{ {
find: "sdk", find: "sdk",
replacement: path.resolve("./src/sdk"), replacement: path.resolve("./src/sdk"),