Merge.
This commit is contained in:
parent
4d86df057b
commit
9339213910
|
@ -14,6 +14,9 @@ metadata:
|
|||
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
|
||||
alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.certificateArn }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.securityGroups }}
|
||||
alb.ingress.kubernetes.io/security-groups: {{ .Values.ingress.securityGroups }}
|
||||
{{- end }}
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@budibase/nano": "10.1.1",
|
||||
"@budibase/types": "2.2.12-alpha.71",
|
||||
"@budibase/types": "^2.3.0",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-cloudfront-sign": "2.2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "1.2.1",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@spectrum-css/accordion": "3.0.24",
|
||||
"@spectrum-css/actionbutton": "1.0.1",
|
||||
"@spectrum-css/actiongroup": "1.0.1",
|
||||
|
|
|
@ -76,13 +76,6 @@
|
|||
}
|
||||
// If time only set date component to 2000-01-01
|
||||
if (timeOnly) {
|
||||
// Classic flackpickr causing issues.
|
||||
// When selecting a value for the first time for a "time only" field,
|
||||
// the time is always offset by 1 hour for some reason (regardless of time
|
||||
// zone) so we need to correct it.
|
||||
if (!value && newValue) {
|
||||
newValue = new Date(dates[0].getTime() + 60 * 60 * 1000).toISOString()
|
||||
}
|
||||
newValue = `2000-01-01T${newValue.split("T")[1]}`
|
||||
}
|
||||
|
||||
|
@ -113,7 +106,7 @@
|
|||
|
||||
const clearDateOnBackspace = event => {
|
||||
if (["Backspace", "Clear", "Delete"].includes(event.key)) {
|
||||
dispatch("change", null)
|
||||
dispatch("change", "")
|
||||
flatpickr.close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,31 @@
|
|||
export let getOptionLabel = option => option
|
||||
export let getOptionValue = option => option
|
||||
export let getOptionTitle = option => option
|
||||
export let sort = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const onChange = e => dispatch("change", e.target.value)
|
||||
|
||||
const getSortedOptions = (options, getLabel, sort) => {
|
||||
if (!options?.length || !Array.isArray(options)) {
|
||||
return []
|
||||
}
|
||||
if (!sort) {
|
||||
return options
|
||||
}
|
||||
return [...options].sort((a, b) => {
|
||||
const labelA = getLabel(a)
|
||||
const labelB = getLabel(b)
|
||||
return labelA > labelB ? 1 : -1
|
||||
})
|
||||
}
|
||||
|
||||
$: parsedOptions = getSortedOptions(options, getOptionLabel, sort)
|
||||
</script>
|
||||
|
||||
<div class={`spectrum-FieldGroup spectrum-FieldGroup--${direction}`}>
|
||||
{#if options && Array.isArray(options)}
|
||||
{#each options as option}
|
||||
{#if parsedOptions && Array.isArray(parsedOptions)}
|
||||
{#each parsedOptions as option}
|
||||
<div
|
||||
title={getOptionTitle(option)}
|
||||
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -58,10 +58,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.2.12-alpha.71",
|
||||
"@budibase/client": "2.2.12-alpha.71",
|
||||
"@budibase/frontend-core": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/bbui": "^2.3.0",
|
||||
"@budibase/client": "^2.3.0",
|
||||
"@budibase/frontend-core": "^2.3.0",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
|
|
|
@ -74,8 +74,19 @@
|
|||
$: schemaFields = Object.values(schema || {})
|
||||
$: queryLimit = tableId?.includes("datasource") ? "∞" : "1000"
|
||||
$: isTrigger = block?.type === "TRIGGER"
|
||||
$: isUpdateRow = stepId === ActionStepID.UPDATE_ROW
|
||||
|
||||
const onChange = Utils.sequential(async (e, key) => {
|
||||
if (e.detail?.tableId) {
|
||||
const tableSchema = getSchemaForTable(e.detail.tableId, {
|
||||
searchableSchema: true,
|
||||
}).schema
|
||||
if (isTestModal) {
|
||||
testData.schema = tableSchema
|
||||
} else {
|
||||
block.inputs.schema = tableSchema
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (isTestModal) {
|
||||
// Special case for webhook, as it requires a body, but the schema already brings back the body's contents
|
||||
|
@ -321,9 +332,17 @@
|
|||
<RowSelector
|
||||
{block}
|
||||
value={inputData[key]}
|
||||
on:change={e => onChange(e, key)}
|
||||
meta={inputData["meta"] || {}}
|
||||
on:change={e => {
|
||||
if (e.detail?.key) {
|
||||
onChange(e, e.detail.key)
|
||||
} else {
|
||||
onChange(e, key)
|
||||
}
|
||||
}}
|
||||
{bindings}
|
||||
{isTestModal}
|
||||
{isUpdateRow}
|
||||
/>
|
||||
{:else if value.customType === "webhookUrl"}
|
||||
<WebhookDisplay
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { tables } from "stores/backend"
|
||||
import { Select } from "@budibase/bbui"
|
||||
import { Select, Checkbox } from "@budibase/bbui"
|
||||
import DrawerBindableInput from "../../common/bindings/DrawerBindableInput.svelte"
|
||||
import AutomationBindingPanel from "../../common/bindings/ServerBindingPanel.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
@ -10,9 +10,11 @@
|
|||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let value
|
||||
export let meta
|
||||
export let bindings
|
||||
export let block
|
||||
export let isTestModal
|
||||
export let isUpdateRow
|
||||
|
||||
$: parsedBindings = bindings.map(binding => {
|
||||
let clone = Object.assign({}, binding)
|
||||
|
@ -97,6 +99,17 @@
|
|||
dispatch("change", value)
|
||||
}
|
||||
|
||||
const onChangeSetting = (e, field) => {
|
||||
let fields = {}
|
||||
fields[field] = {
|
||||
clearRelationships: e.detail,
|
||||
}
|
||||
dispatch("change", {
|
||||
key: "meta",
|
||||
fields,
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure any nullish tableId values get set to empty string so
|
||||
// that the select works
|
||||
$: if (value?.tableId == null) value = { tableId: "" }
|
||||
|
@ -124,6 +137,7 @@
|
|||
{onChange}
|
||||
/>
|
||||
{:else}
|
||||
<div>
|
||||
<svelte:component
|
||||
this={isTestModal ? ModalBindableInput : DrawerBindableInput}
|
||||
placeholder={placeholders[schema.type]}
|
||||
|
@ -139,6 +153,17 @@
|
|||
allowJS={true}
|
||||
updateOnChange={false}
|
||||
/>
|
||||
{#if isUpdateRow && schema.type === "link"}
|
||||
<div class="checkbox-field">
|
||||
<Checkbox
|
||||
value={meta.fields?.[field]?.clearRelationships}
|
||||
text={"Clear relationships if empty?"}
|
||||
size={"S"}
|
||||
on:change={e => onChangeSetting(e, field)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -155,4 +180,12 @@
|
|||
.schema-fields :global(label) {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.checkbox-field {
|
||||
padding-bottom: var(--spacing-s);
|
||||
padding-left: 1px;
|
||||
padding-top: var(--spacing-s);
|
||||
}
|
||||
.checkbox-field :global(label) {
|
||||
text-transform: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
entries = entries.filter(f => f.name !== originalName)
|
||||
}
|
||||
value = entries.reduce((newVals, current) => {
|
||||
newVals[current.name] = current.type
|
||||
newVals[current.name.trim()] = current.type
|
||||
return newVals
|
||||
}, {})
|
||||
dispatch("change", value)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
Modal,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { createEventDispatcher, onMount } from "svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { tables, datasources } from "stores/backend"
|
||||
import { TableNames, UNEDITABLE_USER_FIELDS } from "constants"
|
||||
|
@ -48,7 +48,22 @@
|
|||
const { hide } = getContext(Context.Modal)
|
||||
let fieldDefinitions = cloneDeep(FIELDS)
|
||||
|
||||
export let field = {
|
||||
export let field
|
||||
|
||||
let originalName
|
||||
let linkEditDisabled
|
||||
let primaryDisplay
|
||||
let indexes = [...($tables.selected.indexes || [])]
|
||||
let isCreating
|
||||
|
||||
let table = $tables.selected
|
||||
let confirmDeleteDialog
|
||||
let deletion
|
||||
let savingColumn
|
||||
let deleteColName
|
||||
let jsonSchemaModal
|
||||
|
||||
let editableColumn = {
|
||||
type: "string",
|
||||
constraints: fieldDefinitions.STRING.constraints,
|
||||
|
||||
|
@ -56,48 +71,80 @@
|
|||
fieldName: $tables.selected.name,
|
||||
}
|
||||
|
||||
let originalName = field.name
|
||||
const linkEditDisabled = originalName != null
|
||||
let primaryDisplay =
|
||||
$: if (primaryDisplay) {
|
||||
editableColumn.constraints.presence = { allowEmpty: false }
|
||||
}
|
||||
|
||||
$: if (field && !savingColumn) {
|
||||
editableColumn = cloneDeep(field)
|
||||
originalName = editableColumn.name ? editableColumn.name + "" : null
|
||||
linkEditDisabled = originalName != null
|
||||
isCreating = originalName == null
|
||||
primaryDisplay =
|
||||
$tables.selected.primaryDisplay == null ||
|
||||
$tables.selected.primaryDisplay === field.name
|
||||
let isCreating = originalName == null
|
||||
$tables.selected.primaryDisplay === editableColumn.name
|
||||
}
|
||||
|
||||
let table = $tables.selected
|
||||
let indexes = [...($tables.selected.indexes || [])]
|
||||
let confirmDeleteDialog
|
||||
let deletion
|
||||
let deleteColName
|
||||
let jsonSchemaModal
|
||||
|
||||
$: checkConstraints(field)
|
||||
$: required = !!field?.constraints?.presence || primaryDisplay
|
||||
$: checkConstraints(editableColumn)
|
||||
$: required = !!editableColumn?.constraints?.presence || primaryDisplay
|
||||
$: uneditable =
|
||||
$tables.selected?._id === TableNames.USERS &&
|
||||
UNEDITABLE_USER_FIELDS.includes(field.name)
|
||||
UNEDITABLE_USER_FIELDS.includes(editableColumn.name)
|
||||
$: invalid =
|
||||
!field.name ||
|
||||
(field.type === LINK_TYPE && !field.tableId) ||
|
||||
!editableColumn?.name ||
|
||||
(editableColumn?.type === LINK_TYPE && !editableColumn?.tableId) ||
|
||||
Object.keys(errors).length !== 0
|
||||
$: errors = checkErrors(field)
|
||||
$: errors = checkErrors(editableColumn)
|
||||
$: datasource = $datasources.list.find(
|
||||
source => source._id === table?.sourceId
|
||||
)
|
||||
|
||||
const getTableAutoColumnTypes = table => {
|
||||
return Object.keys(table?.schema).reduce((acc, key) => {
|
||||
let fieldSchema = table?.schema[key]
|
||||
if (fieldSchema.autocolumn) {
|
||||
acc.push(fieldSchema.subtype)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
|
||||
let autoColumnInfo = getAutoColumnInformation()
|
||||
|
||||
$: tableAutoColumnsTypes = getTableAutoColumnTypes($tables?.selected)
|
||||
$: availableAutoColumns = Object.keys(autoColumnInfo).reduce((acc, key) => {
|
||||
if (!tableAutoColumnsTypes.includes(key)) {
|
||||
acc[key] = autoColumnInfo[key]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
$: availableAutoColumnKeys = availableAutoColumns
|
||||
? Object.keys(availableAutoColumns)
|
||||
: []
|
||||
|
||||
$: autoColumnOptions = editableColumn.autocolumn
|
||||
? autoColumnInfo
|
||||
: availableAutoColumns
|
||||
|
||||
// used to select what different options can be displayed for column type
|
||||
$: canBeSearched =
|
||||
field.type !== LINK_TYPE &&
|
||||
field.type !== JSON_TYPE &&
|
||||
field.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY &&
|
||||
field.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY &&
|
||||
field.type !== FORMULA_TYPE
|
||||
editableColumn?.type !== LINK_TYPE &&
|
||||
editableColumn?.type !== JSON_TYPE &&
|
||||
editableColumn?.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY &&
|
||||
editableColumn?.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY &&
|
||||
editableColumn?.type !== FORMULA_TYPE
|
||||
$: canBeDisplay =
|
||||
field.type !== LINK_TYPE &&
|
||||
field.type !== AUTO_TYPE &&
|
||||
field.type !== JSON_TYPE
|
||||
editableColumn?.type !== LINK_TYPE &&
|
||||
editableColumn?.type !== AUTO_TYPE &&
|
||||
editableColumn?.type !== JSON_TYPE &&
|
||||
!editableColumn.autocolumn
|
||||
$: canBeRequired =
|
||||
field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE
|
||||
$: relationshipOptions = getRelationshipOptions(field)
|
||||
editableColumn?.type !== LINK_TYPE &&
|
||||
!uneditable &&
|
||||
editableColumn?.type !== AUTO_TYPE &&
|
||||
!editableColumn.autocolumn
|
||||
$: relationshipOptions = getRelationshipOptions(editableColumn)
|
||||
$: external = table.type === "external"
|
||||
// in the case of internal tables the sourceId will just be undefined
|
||||
$: tableOptions = $tables.list.filter(
|
||||
|
@ -108,76 +155,90 @@
|
|||
)
|
||||
$: typeEnabled =
|
||||
!originalName ||
|
||||
(originalName && SWITCHABLE_TYPES.indexOf(field.type) !== -1)
|
||||
(originalName &&
|
||||
SWITCHABLE_TYPES.indexOf(editableColumn.type) !== -1 &&
|
||||
!editableColumn?.autocolumn)
|
||||
|
||||
async function saveColumn() {
|
||||
if (field.type === AUTO_TYPE) {
|
||||
field = buildAutoColumn($tables.selected.name, field.name, field.subtype)
|
||||
savingColumn = true
|
||||
if (errors?.length) {
|
||||
return
|
||||
}
|
||||
if (field.type !== LINK_TYPE) {
|
||||
delete field.fieldName
|
||||
|
||||
let saveColumn = cloneDeep(editableColumn)
|
||||
|
||||
if (saveColumn.type === AUTO_TYPE) {
|
||||
saveColumn = buildAutoColumn(
|
||||
$tables.selected.name,
|
||||
saveColumn.name,
|
||||
saveColumn.subtype
|
||||
)
|
||||
}
|
||||
if (saveColumn.type !== LINK_TYPE) {
|
||||
delete saveColumn.fieldName
|
||||
}
|
||||
try {
|
||||
await tables.saveField({
|
||||
originalName,
|
||||
field,
|
||||
field: saveColumn,
|
||||
primaryDisplay,
|
||||
indexes,
|
||||
})
|
||||
dispatch("updatecolumns")
|
||||
} catch (err) {
|
||||
notifications.error("Error saving column")
|
||||
console.log(err)
|
||||
notifications.error(`Error saving column: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
field.name = originalName
|
||||
editableColumn.name = originalName
|
||||
}
|
||||
|
||||
function deleteColumn() {
|
||||
try {
|
||||
field.name = deleteColName
|
||||
if (field.name === $tables.selected.primaryDisplay) {
|
||||
editableColumn.name = deleteColName
|
||||
if (editableColumn.name === $tables.selected.primaryDisplay) {
|
||||
notifications.error("You cannot delete the display column")
|
||||
} else {
|
||||
tables.deleteField(field)
|
||||
notifications.success(`Column ${field.name} deleted.`)
|
||||
tables.deleteField(editableColumn)
|
||||
notifications.success(`Column ${editableColumn.name} deleted.`)
|
||||
confirmDeleteDialog.hide()
|
||||
hide()
|
||||
deletion = false
|
||||
dispatch("updatecolumns")
|
||||
}
|
||||
} catch (error) {
|
||||
notifications.error("Error deleting column")
|
||||
notifications.error(`Error deleting column: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
function handleTypeChange(event) {
|
||||
// remove any extra fields that may not be related to this type
|
||||
delete field.autocolumn
|
||||
delete field.subtype
|
||||
delete field.tableId
|
||||
delete field.relationshipType
|
||||
delete field.formulaType
|
||||
delete editableColumn.autocolumn
|
||||
delete editableColumn.subtype
|
||||
delete editableColumn.tableId
|
||||
delete editableColumn.relationshipType
|
||||
delete editableColumn.formulaType
|
||||
|
||||
// Add in defaults and initial definition
|
||||
const definition = fieldDefinitions[event.detail?.toUpperCase()]
|
||||
if (definition?.constraints) {
|
||||
field.constraints = definition.constraints
|
||||
editableColumn.constraints = definition.constraints
|
||||
}
|
||||
|
||||
// Default relationships many to many
|
||||
if (field.type === LINK_TYPE) {
|
||||
field.relationshipType = RelationshipTypes.MANY_TO_MANY
|
||||
if (editableColumn.type === LINK_TYPE) {
|
||||
editableColumn.relationshipType = RelationshipTypes.MANY_TO_MANY
|
||||
}
|
||||
if (field.type === FORMULA_TYPE) {
|
||||
field.formulaType = "dynamic"
|
||||
if (editableColumn.type === FORMULA_TYPE) {
|
||||
editableColumn.formulaType = "dynamic"
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeRequired(e) {
|
||||
const req = e.detail
|
||||
field.constraints.presence = req ? { allowEmpty: false } : false
|
||||
editableColumn.constraints.presence = req ? { allowEmpty: false } : false
|
||||
required = req
|
||||
}
|
||||
|
||||
|
@ -185,17 +246,17 @@
|
|||
const isPrimary = e.detail
|
||||
// primary display is always required
|
||||
if (isPrimary) {
|
||||
field.constraints.presence = { allowEmpty: false }
|
||||
editableColumn.constraints.presence = { allowEmpty: false }
|
||||
}
|
||||
}
|
||||
|
||||
function onChangePrimaryIndex(e) {
|
||||
indexes = e.detail ? [field.name] : []
|
||||
indexes = e.detail ? [editableColumn.name] : []
|
||||
}
|
||||
|
||||
function onChangeSecondaryIndex(e) {
|
||||
if (e.detail) {
|
||||
indexes[1] = field.name
|
||||
indexes[1] = editableColumn.name
|
||||
} else {
|
||||
indexes = indexes.slice(0, 1)
|
||||
}
|
||||
|
@ -246,11 +307,14 @@
|
|||
}
|
||||
|
||||
function getAllowedTypes() {
|
||||
if (originalName && ALLOWABLE_STRING_TYPES.indexOf(field.type) !== -1) {
|
||||
if (
|
||||
originalName &&
|
||||
ALLOWABLE_STRING_TYPES.indexOf(editableColumn.type) !== -1
|
||||
) {
|
||||
return ALLOWABLE_STRING_OPTIONS
|
||||
} else if (
|
||||
originalName &&
|
||||
ALLOWABLE_NUMBER_TYPES.indexOf(field.type) !== -1
|
||||
ALLOWABLE_NUMBER_TYPES.indexOf(editableColumn.type) !== -1
|
||||
) {
|
||||
return ALLOWABLE_NUMBER_OPTIONS
|
||||
} else if (!external) {
|
||||
|
@ -275,6 +339,9 @@
|
|||
}
|
||||
|
||||
function checkConstraints(fieldToCheck) {
|
||||
if (!fieldToCheck) {
|
||||
return
|
||||
}
|
||||
// most types need this, just make sure its always present
|
||||
if (fieldToCheck && !fieldToCheck.constraints) {
|
||||
fieldToCheck.constraints = {}
|
||||
|
@ -296,10 +363,16 @@
|
|||
}
|
||||
|
||||
function checkErrors(fieldInfo) {
|
||||
if (!editableColumn) {
|
||||
return {}
|
||||
}
|
||||
function inUse(tbl, column, ogName = null) {
|
||||
return Object.keys(tbl?.schema || {}).some(
|
||||
key => key !== ogName && key === column
|
||||
)
|
||||
const parsedColumn = column ? column.toLowerCase().trim() : column
|
||||
|
||||
return Object.keys(tbl?.schema || {}).some(key => {
|
||||
let lowerKey = key.toLowerCase()
|
||||
return lowerKey !== ogName?.toLowerCase() && lowerKey === parsedColumn
|
||||
})
|
||||
}
|
||||
const newError = {}
|
||||
if (!external && fieldInfo.name?.startsWith("_")) {
|
||||
|
@ -313,6 +386,11 @@
|
|||
} else if (inUse($tables.selected, fieldInfo.name, originalName)) {
|
||||
newError.name = `Column name already in use.`
|
||||
}
|
||||
|
||||
if (fieldInfo.type == "auto" && !fieldInfo.subtype) {
|
||||
newError.subtype = `Auto Column requires a type`
|
||||
}
|
||||
|
||||
if (fieldInfo.fieldName && fieldInfo.tableId) {
|
||||
const relatedTable = $tables.list.find(
|
||||
tbl => tbl._id === fieldInfo.tableId
|
||||
|
@ -323,12 +401,6 @@
|
|||
}
|
||||
return newError
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (primaryDisplay) {
|
||||
field.constraints.presence = { allowEmpty: false }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
|
@ -340,19 +412,26 @@
|
|||
>
|
||||
<Input
|
||||
label="Name"
|
||||
bind:value={field.name}
|
||||
disabled={uneditable || (linkEditDisabled && field.type === LINK_TYPE)}
|
||||
bind:value={editableColumn.name}
|
||||
disabled={uneditable ||
|
||||
(linkEditDisabled && editableColumn.type === LINK_TYPE)}
|
||||
error={errors?.name}
|
||||
/>
|
||||
|
||||
<Select
|
||||
disabled={!typeEnabled}
|
||||
label="Type"
|
||||
bind:value={field.type}
|
||||
bind:value={editableColumn.type}
|
||||
on:change={handleTypeChange}
|
||||
options={getAllowedTypes()}
|
||||
getOptionLabel={field => field.name}
|
||||
getOptionValue={field => field.type}
|
||||
isOptionEnabled={option => {
|
||||
if (option.type == AUTO_TYPE) {
|
||||
return availableAutoColumnKeys?.length > 0
|
||||
}
|
||||
return true
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if canBeRequired || canBeDisplay}
|
||||
|
@ -381,32 +460,32 @@
|
|||
<div>
|
||||
<Label>Search Indexes</Label>
|
||||
<Toggle
|
||||
value={indexes[0] === field.name}
|
||||
disabled={indexes[1] === field.name}
|
||||
value={indexes[0] === editableColumn.name}
|
||||
disabled={indexes[1] === editableColumn.name}
|
||||
on:change={onChangePrimaryIndex}
|
||||
text="Primary"
|
||||
/>
|
||||
<Toggle
|
||||
value={indexes[1] === field.name}
|
||||
disabled={!indexes[0] || indexes[0] === field.name}
|
||||
value={indexes[1] === editableColumn.name}
|
||||
disabled={!indexes[0] || indexes[0] === editableColumn.name}
|
||||
on:change={onChangeSecondaryIndex}
|
||||
text="Secondary"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if field.type === "string"}
|
||||
{#if editableColumn.type === "string"}
|
||||
<Input
|
||||
type="number"
|
||||
label="Max Length"
|
||||
bind:value={field.constraints.length.maximum}
|
||||
bind:value={editableColumn.constraints.length.maximum}
|
||||
/>
|
||||
{:else if field.type === "options"}
|
||||
{:else if editableColumn.type === "options"}
|
||||
<ValuesList
|
||||
label="Options (one per line)"
|
||||
bind:values={field.constraints.inclusion}
|
||||
bind:values={editableColumn.constraints.inclusion}
|
||||
/>
|
||||
{:else if field.type === "longform"}
|
||||
{:else if editableColumn.type === "longform"}
|
||||
<div>
|
||||
<Label
|
||||
size="M"
|
||||
|
@ -415,21 +494,24 @@
|
|||
Formatting
|
||||
</Label>
|
||||
<Toggle
|
||||
bind:value={field.useRichText}
|
||||
bind:value={editableColumn.useRichText}
|
||||
text="Enable rich text support (markdown)"
|
||||
/>
|
||||
</div>
|
||||
{:else if field.type === "array"}
|
||||
{:else if editableColumn.type === "array"}
|
||||
<ValuesList
|
||||
label="Options (one per line)"
|
||||
bind:values={field.constraints.inclusion}
|
||||
bind:values={editableColumn.constraints.inclusion}
|
||||
/>
|
||||
{:else if field.type === "datetime"}
|
||||
{:else if editableColumn.type === "datetime" && !editableColumn.autocolumn}
|
||||
<DatePicker
|
||||
label="Earliest"
|
||||
bind:value={field.constraints.datetime.earliest}
|
||||
bind:value={editableColumn.constraints.datetime.earliest}
|
||||
/>
|
||||
<DatePicker
|
||||
label="Latest"
|
||||
bind:value={editableColumn.constraints.datetime.latest}
|
||||
/>
|
||||
<DatePicker label="Latest" bind:value={field.constraints.datetime.latest} />
|
||||
{#if datasource?.source !== "ORACLE" && datasource?.source !== "SQL_SERVER"}
|
||||
<div>
|
||||
<Label
|
||||
|
@ -439,25 +521,28 @@
|
|||
>
|
||||
Time zones
|
||||
</Label>
|
||||
<Toggle bind:value={field.ignoreTimezones} text="Ignore time zones" />
|
||||
<Toggle
|
||||
bind:value={editableColumn.ignoreTimezones}
|
||||
text="Ignore time zones"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if field.type === "number"}
|
||||
{:else if editableColumn.type === "number" && !editableColumn.autocolumn}
|
||||
<Input
|
||||
type="number"
|
||||
label="Min Value"
|
||||
bind:value={field.constraints.numericality.greaterThanOrEqualTo}
|
||||
bind:value={editableColumn.constraints.numericality.greaterThanOrEqualTo}
|
||||
/>
|
||||
<Input
|
||||
type="number"
|
||||
label="Max Value"
|
||||
bind:value={field.constraints.numericality.lessThanOrEqualTo}
|
||||
bind:value={editableColumn.constraints.numericality.lessThanOrEqualTo}
|
||||
/>
|
||||
{:else if field.type === "link"}
|
||||
{:else if editableColumn.type === "link"}
|
||||
<Select
|
||||
label="Table"
|
||||
disabled={linkEditDisabled}
|
||||
bind:value={field.tableId}
|
||||
bind:value={editableColumn.tableId}
|
||||
options={tableOptions}
|
||||
getOptionLabel={table => table.name}
|
||||
getOptionValue={table => table._id}
|
||||
|
@ -466,7 +551,7 @@
|
|||
<RadioGroup
|
||||
disabled={linkEditDisabled}
|
||||
label="Define the relationship"
|
||||
bind:value={field.relationshipType}
|
||||
bind:value={editableColumn.relationshipType}
|
||||
options={relationshipOptions}
|
||||
getOptionLabel={option => option.name}
|
||||
getOptionValue={option => option.value}
|
||||
|
@ -476,14 +561,14 @@
|
|||
<Input
|
||||
disabled={linkEditDisabled}
|
||||
label={`Column name in other table`}
|
||||
bind:value={field.fieldName}
|
||||
bind:value={editableColumn.fieldName}
|
||||
error={errors.relatedName}
|
||||
/>
|
||||
{:else if field.type === FORMULA_TYPE}
|
||||
{:else if editableColumn.type === FORMULA_TYPE}
|
||||
{#if !table.sql}
|
||||
<Select
|
||||
label="Formula type"
|
||||
bind:value={field.formulaType}
|
||||
bind:value={editableColumn.formulaType}
|
||||
options={[
|
||||
{ label: "Dynamic", value: "dynamic" },
|
||||
{ label: "Static", value: "static" },
|
||||
|
@ -497,25 +582,28 @@
|
|||
<ModalBindableInput
|
||||
title="Formula"
|
||||
label="Formula"
|
||||
value={field.formula}
|
||||
on:change={e => (field.formula = e.detail)}
|
||||
value={editableColumn.formula}
|
||||
on:change={e => (editableColumn.formula = e.detail)}
|
||||
bindings={getBindings({ table })}
|
||||
allowJS
|
||||
/>
|
||||
{:else if field.type === AUTO_TYPE}
|
||||
<Select
|
||||
label="Auto column type"
|
||||
value={field.subtype}
|
||||
on:change={e => (field.subtype = e.detail)}
|
||||
options={Object.entries(getAutoColumnInformation())}
|
||||
getOptionLabel={option => option[1].name}
|
||||
getOptionValue={option => option[0]}
|
||||
/>
|
||||
{:else if field.type === JSON_TYPE}
|
||||
{:else if editableColumn.type === JSON_TYPE}
|
||||
<Button primary text on:click={openJsonSchemaEditor}
|
||||
>Open schema editor</Button
|
||||
>
|
||||
{/if}
|
||||
{#if editableColumn.type === AUTO_TYPE || editableColumn.autocolumn}
|
||||
<Select
|
||||
label="Auto column type"
|
||||
value={editableColumn.subtype}
|
||||
on:change={e => (editableColumn.subtype = e.detail)}
|
||||
options={Object.entries(autoColumnOptions)}
|
||||
getOptionLabel={option => option[1].name}
|
||||
getOptionValue={option => option[0]}
|
||||
disabled={!availableAutoColumnKeys?.length || editableColumn.autocolumn}
|
||||
error={errors?.subtype}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div slot="footer">
|
||||
{#if !uneditable && originalName != null}
|
||||
|
@ -525,11 +613,11 @@
|
|||
</ModalContent>
|
||||
<Modal bind:this={jsonSchemaModal}>
|
||||
<JSONSchemaModal
|
||||
schema={field.schema}
|
||||
json={field.json}
|
||||
schema={editableColumn.schema}
|
||||
json={editableColumn.json}
|
||||
on:save={({ detail }) => {
|
||||
field.schema = detail.schema
|
||||
field.json = detail.json
|
||||
editableColumn.schema = detail.schema
|
||||
editableColumn.json = detail.json
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
|
|
|
@ -106,4 +106,8 @@
|
|||
border: var(--border-light);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.control :global(.spectrum-Textfield-input) {
|
||||
padding-right: 40px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -77,8 +77,18 @@
|
|||
}
|
||||
|
||||
const deleteAction = index => {
|
||||
// Check if we're deleting the selected action
|
||||
const selectedIndex = actions.indexOf(selectedAction)
|
||||
const isSelected = index === selectedIndex
|
||||
|
||||
// Delete the action
|
||||
actions.splice(index, 1)
|
||||
actions = actions
|
||||
|
||||
// Select a new action if we deleted the selected one
|
||||
if (isSelected) {
|
||||
selectedAction = actions?.length ? actions[0] : null
|
||||
}
|
||||
}
|
||||
|
||||
const toggleActionList = () => {
|
||||
|
|
|
@ -36,7 +36,13 @@
|
|||
$: selectedSchema = selectedAutomation?.schema
|
||||
|
||||
const onFieldsChanged = e => {
|
||||
parameters.fields = e.detail
|
||||
parameters.fields = Object.entries(e.detail || {}).reduce(
|
||||
(acc, [key, value]) => {
|
||||
acc[key.trim()] = value
|
||||
return acc
|
||||
},
|
||||
{}
|
||||
)
|
||||
}
|
||||
|
||||
const setNew = () => {
|
||||
|
|
|
@ -1,9 +1,45 @@
|
|||
<script>
|
||||
import TableDataTable from "components/backend/DataTable/DataTable.svelte"
|
||||
import { tables, database } from "stores/backend"
|
||||
import { Banner } from "@budibase/bbui"
|
||||
|
||||
const verifyAutocolumns = table => {
|
||||
// Check for duplicates
|
||||
return Object.values(table?.schema || {}).reduce((acc, fieldSchema) => {
|
||||
if (!fieldSchema.autocolumn || !fieldSchema.subtype) {
|
||||
return acc
|
||||
}
|
||||
let fieldKey = fieldSchema.tableId
|
||||
? `${fieldSchema.tableId}-${fieldSchema.subtype}`
|
||||
: fieldSchema.subtype
|
||||
acc[fieldKey] = acc[fieldKey] || []
|
||||
acc[fieldKey].push(fieldSchema)
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
$: autoColumnStatus = verifyAutocolumns($tables?.selected)
|
||||
$: duplicates = Object.values(autoColumnStatus).reduce((acc, status) => {
|
||||
if (status.length > 1) {
|
||||
acc = [...acc, ...status]
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
$: invalidColumnText = duplicates.map(entry => {
|
||||
return `${entry.name} (${entry.subtype})`
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if $database?._id && $tables?.selected}
|
||||
{#if $database?._id && $tables?.selected?.name}
|
||||
{#if duplicates?.length}
|
||||
<div class="alert-wrap">
|
||||
<Banner type="warning" showCloseButton={false}>
|
||||
{`Schema Invalid - There are duplicate auto column types defined in this schema.
|
||||
Please delete the duplicate entries where appropriate: -
|
||||
${invalidColumnText.join(", ")}`}
|
||||
</Banner>
|
||||
</div>
|
||||
{/if}
|
||||
<TableDataTable />
|
||||
{:else}
|
||||
<i>Create your first table to start building</i>
|
||||
|
@ -15,4 +51,11 @@
|
|||
color: var(--grey-5);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.alert-wrap {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.alert-wrap :global(> *) {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
{#if $selectedComponent}
|
||||
{#key $selectedComponent._id}
|
||||
<Panel {title} icon={componentDefinition?.icon} borderLeft>
|
||||
{#if componentDefinition.info}
|
||||
{#if componentDefinition?.info}
|
||||
<ComponentInfoSection {componentDefinition} />
|
||||
{/if}
|
||||
<ComponentSettingsSection
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
@ -26,9 +26,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/types": "2.2.12-alpha.71",
|
||||
"@budibase/backend-core": "^2.3.0",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@budibase/types": "^2.3.0",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.2.12-alpha.71",
|
||||
"@budibase/frontend-core": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/bbui": "^2.3.0",
|
||||
"@budibase/frontend-core": "^2.3.0",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -171,6 +171,15 @@
|
|||
$: pad = pad || (interactive && hasChildren && inDndPath)
|
||||
$: $dndIsDragging, (pad = false)
|
||||
|
||||
// Determine whether we should render a skeleton loader for this component
|
||||
$: showSkeleton =
|
||||
$loading &&
|
||||
definition.name !== "Screenslot" &&
|
||||
children.length === 0 &&
|
||||
!instance._blockElementHasChildren &&
|
||||
!definition.block &&
|
||||
definition.skeleton !== false
|
||||
|
||||
// Update component context
|
||||
$: store.set({
|
||||
id,
|
||||
|
@ -473,14 +482,6 @@
|
|||
componentStore.actions.unregisterInstance(id)
|
||||
}
|
||||
})
|
||||
|
||||
$: showSkeleton =
|
||||
$loading &&
|
||||
definition.name !== "Screenslot" &&
|
||||
children.length === 0 &&
|
||||
!instance._blockElementHasChildren &&
|
||||
!definition.block &&
|
||||
definition.skeleton !== false
|
||||
</script>
|
||||
|
||||
{#if showSkeleton}
|
||||
|
|
|
@ -11,20 +11,23 @@
|
|||
export let limit
|
||||
export let paginate
|
||||
|
||||
const loading = writable(false)
|
||||
|
||||
const { styleable, Provider, ActionTypes, API } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
// Update loading state
|
||||
const parentLoading = getContext("loading")
|
||||
const loading = writable(true)
|
||||
setContext("loading", loading)
|
||||
|
||||
// We need to manage our lucene query manually as we want to allow components
|
||||
// to extend it
|
||||
let queryExtensions = {}
|
||||
$: defaultQuery = LuceneUtils.buildLuceneQuery(filter)
|
||||
$: query = extendQuery(defaultQuery, queryExtensions)
|
||||
|
||||
// Keep our data fetch instance up to date
|
||||
$: fetch = createFetch(dataSource)
|
||||
$: fetch.update({
|
||||
// Fetch data and refresh when needed
|
||||
$: fetch = createFetch(dataSource, $parentLoading)
|
||||
$: updateFetch({
|
||||
query,
|
||||
sortColumn,
|
||||
sortOrder,
|
||||
|
@ -32,6 +35,9 @@
|
|||
paginate,
|
||||
})
|
||||
|
||||
// Keep loading context updated
|
||||
$: loading.set($parentLoading || !$fetch.loaded)
|
||||
|
||||
// Build our action context
|
||||
$: actions = [
|
||||
{
|
||||
|
@ -80,14 +86,21 @@
|
|||
sortColumn: $fetch.sortColumn,
|
||||
sortOrder: $fetch.sortOrder,
|
||||
},
|
||||
limit: limit,
|
||||
limit,
|
||||
}
|
||||
|
||||
const parentLoading = getContext("loading")
|
||||
setContext("loading", loading)
|
||||
$: loading.set($parentLoading || !$fetch.loaded)
|
||||
const createFetch = (datasource, parentLoading) => {
|
||||
// Return a dummy fetch if parent is still loading. We do this so that we
|
||||
// can still properly subscribe to a valid fetch object and check all
|
||||
// properties, but we want to avoid fetching the real data until all parents
|
||||
// have finished loading.
|
||||
// This logic is only needed due to skeleton loaders, as previously we
|
||||
// simply blocked component rendering until data was ready.
|
||||
if (parentLoading) {
|
||||
return fetchData({ API })
|
||||
}
|
||||
|
||||
const createFetch = datasource => {
|
||||
// Otherwise return the real thing
|
||||
return fetchData({
|
||||
API,
|
||||
datasource,
|
||||
|
@ -101,6 +114,14 @@
|
|||
})
|
||||
}
|
||||
|
||||
const updateFetch = opts => {
|
||||
// Only update fetch if parents have stopped loading. Otherwise we will
|
||||
// trigger a fetch of the real data before parents are ready.
|
||||
if (!$parentLoading) {
|
||||
fetch.update(opts)
|
||||
}
|
||||
}
|
||||
|
||||
const addQueryExtension = (key, extension) => {
|
||||
if (!key || !extension) {
|
||||
return
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { getContext, setContext } from "svelte"
|
||||
import InnerForm from "./InnerForm.svelte"
|
||||
import { Helpers } from "@budibase/bbui"
|
||||
import { writable } from "svelte/store"
|
||||
|
||||
export let dataSource
|
||||
export let theme
|
||||
|
@ -20,6 +21,12 @@
|
|||
const context = getContext("context")
|
||||
const { API, fetchDatasourceSchema } = getContext("sdk")
|
||||
|
||||
// Forms also use loading context as they require loading a schema
|
||||
const parentLoading = getContext("loading")
|
||||
const loading = writable(true)
|
||||
setContext("loading", loading)
|
||||
|
||||
let loaded = false
|
||||
let schema
|
||||
let table
|
||||
|
||||
|
@ -29,6 +36,7 @@
|
|||
$: resetKey = Helpers.hashString(
|
||||
schemaKey + JSON.stringify(initialValues) + disabled
|
||||
)
|
||||
$: loading.set($parentLoading || !loaded)
|
||||
|
||||
// Returns the closes data context which isn't a built in context
|
||||
const getInitialValues = (type, dataSource, context) => {
|
||||
|
@ -60,6 +68,9 @@
|
|||
}
|
||||
const res = await fetchDatasourceSchema(dataSource)
|
||||
schema = res || {}
|
||||
if (!loaded) {
|
||||
loaded = true
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a predictable string that uniquely identifies a schema. We can't
|
||||
|
|
|
@ -128,21 +128,15 @@
|
|||
return fields.find(field => get(field).name === name)
|
||||
}
|
||||
|
||||
const getDefault = (defaultValue, schema, type) => {
|
||||
// Remove any values not present in the field schema
|
||||
// Convert any values supplied to string
|
||||
if (Array.isArray(defaultValue) && type == "array" && schema) {
|
||||
return defaultValue.reduce((acc, entry) => {
|
||||
let processedOption = String(entry)
|
||||
let schemaOptions = schema.constraints.inclusion
|
||||
if (schemaOptions.indexOf(processedOption) > -1) {
|
||||
acc.push(processedOption)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
} else {
|
||||
return defaultValue
|
||||
// Sanitises a value by ensuring it doesn't contain any invalid data
|
||||
const sanitiseValue = (value, schema, type) => {
|
||||
// Check arrays - remove any values not present in the field schema and
|
||||
// convert any values supplied to strings
|
||||
if (Array.isArray(value) && type === "array" && schema) {
|
||||
const options = schema?.constraints.inclusion || []
|
||||
return value.map(opt => String(opt)).filter(opt => options.includes(opt))
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
const formApi = {
|
||||
|
@ -160,7 +154,6 @@
|
|||
|
||||
// Create validation function based on field schema
|
||||
const schemaConstraints = schema?.[field]?.constraints
|
||||
|
||||
const validator = disableValidation
|
||||
? null
|
||||
: createValidatorFromConstraints(
|
||||
|
@ -170,10 +163,11 @@
|
|||
table
|
||||
)
|
||||
|
||||
const parsedDefault = getDefault(defaultValue, schema?.[field], type)
|
||||
// Sanitise the default value to ensure it doesn't contain invalid data
|
||||
defaultValue = sanitiseValue(defaultValue, schema?.[field], type)
|
||||
|
||||
// If we've already registered this field then keep some existing state
|
||||
let initialValue = Helpers.deepGet(initialValues, field) ?? parsedDefault
|
||||
let initialValue = Helpers.deepGet(initialValues, field) ?? defaultValue
|
||||
let initialError = null
|
||||
let fieldId = `id-${Helpers.uuid()}`
|
||||
const existingField = getField(field)
|
||||
|
@ -183,7 +177,9 @@
|
|||
|
||||
// Determine the initial value for this field, reusing the current
|
||||
// value if one exists
|
||||
initialValue = fieldState.value ?? initialValue
|
||||
if (fieldState.value != null && fieldState.value !== "") {
|
||||
initialValue = fieldState.value
|
||||
}
|
||||
|
||||
// If this field has already been registered and we previously had an
|
||||
// error set, then re-run the validator to see if we can unset it
|
||||
|
@ -206,11 +202,11 @@
|
|||
error: initialError,
|
||||
disabled:
|
||||
disabled || fieldDisabled || (isAutoColumn && !editAutoColumns),
|
||||
defaultValue: parsedDefault,
|
||||
defaultValue,
|
||||
validator,
|
||||
lastUpdate: Date.now(),
|
||||
},
|
||||
fieldApi: makeFieldApi(field, parsedDefault),
|
||||
fieldApi: makeFieldApi(field),
|
||||
fieldSchema: schema?.[field] ?? {},
|
||||
})
|
||||
|
||||
|
@ -225,18 +221,9 @@
|
|||
return fieldInfo
|
||||
},
|
||||
validate: () => {
|
||||
let valid = true
|
||||
let validationFields = fields
|
||||
|
||||
validationFields = fields.filter(f => get(f).step === get(currentStep))
|
||||
|
||||
// Validate fields and check if any are invalid
|
||||
validationFields.forEach(field => {
|
||||
if (!get(field).fieldApi.validate()) {
|
||||
valid = false
|
||||
}
|
||||
})
|
||||
return valid
|
||||
return fields
|
||||
.filter(field => get(field).step === get(currentStep))
|
||||
.every(field => get(field).fieldApi.validate())
|
||||
},
|
||||
reset: () => {
|
||||
// Reset the form by resetting each individual field
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
getOptionLabel={flatOptions ? x => x : x => x.label}
|
||||
getOptionTitle={flatOptions ? x => x : x => x.label}
|
||||
getOptionValue={flatOptions ? x => x : x => x.value}
|
||||
{sort}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.2.12-alpha.71",
|
||||
"@budibase/bbui": "^2.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/sdk",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase Public API SDK",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -43,11 +43,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "2.2.12-alpha.71",
|
||||
"@budibase/client": "2.2.12-alpha.71",
|
||||
"@budibase/pro": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/types": "2.2.12-alpha.71",
|
||||
"@budibase/backend-core": "^2.3.0",
|
||||
"@budibase/client": "^2.3.0",
|
||||
"@budibase/pro": "2.3.0",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@budibase/types": "^2.3.0",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -315,7 +315,13 @@ export async function checkForViewUpdates(
|
|||
|
||||
// Update view if required
|
||||
if (needsUpdated) {
|
||||
const newViewTemplate = viewTemplate(view.meta)
|
||||
const groupByField: any = Object.values(table.schema).find(
|
||||
(field: any) => field.name == view.groupBy
|
||||
)
|
||||
const newViewTemplate = viewTemplate(
|
||||
view.meta,
|
||||
groupByField?.type === FieldTypes.ARRAY
|
||||
)
|
||||
await saveView(null, view.name, newViewTemplate)
|
||||
if (!newViewTemplate.meta.schema) {
|
||||
newViewTemplate.meta.schema = table.schema
|
||||
|
|
|
@ -6,8 +6,9 @@ import { fetchView } from "../row"
|
|||
import { context, events } from "@budibase/backend-core"
|
||||
import { DocumentType } from "../../../db/utils"
|
||||
import sdk from "../../../sdk"
|
||||
import { FieldTypes } from "../../../constants"
|
||||
import {
|
||||
BBContext,
|
||||
Ctx,
|
||||
Row,
|
||||
Table,
|
||||
TableExportFormat,
|
||||
|
@ -18,14 +19,22 @@ import { cleanExportRows } from "../row/utils"
|
|||
|
||||
const { cloneDeep, isEqual } = require("lodash")
|
||||
|
||||
export async function fetch(ctx: BBContext) {
|
||||
export async function fetch(ctx: Ctx) {
|
||||
ctx.body = await getViews()
|
||||
}
|
||||
|
||||
export async function save(ctx: BBContext) {
|
||||
export async function save(ctx: Ctx) {
|
||||
const db = context.getAppDB()
|
||||
const { originalName, ...viewToSave } = ctx.request.body
|
||||
const view = viewTemplate(viewToSave)
|
||||
|
||||
const existingTable = await db.get(ctx.request.body.tableId)
|
||||
const table = cloneDeep(existingTable)
|
||||
|
||||
const groupByField: any = Object.values(table.schema).find(
|
||||
(field: any) => field.name == viewToSave.groupBy
|
||||
)
|
||||
|
||||
const view = viewTemplate(viewToSave, groupByField?.type === FieldTypes.ARRAY)
|
||||
const viewName = viewToSave.name
|
||||
|
||||
if (!viewName) {
|
||||
|
@ -35,8 +44,6 @@ export async function save(ctx: BBContext) {
|
|||
await saveView(originalName, viewName, view)
|
||||
|
||||
// add views to table document
|
||||
const existingTable = await db.get(ctx.request.body.tableId)
|
||||
const table = cloneDeep(existingTable)
|
||||
if (!table.views) table.views = {}
|
||||
if (!view.meta.schema) {
|
||||
view.meta.schema = table.schema
|
||||
|
@ -111,7 +118,7 @@ async function handleViewEvents(existingView: View, newView: View) {
|
|||
await filterEvents(existingView, newView)
|
||||
}
|
||||
|
||||
export async function destroy(ctx: BBContext) {
|
||||
export async function destroy(ctx: Ctx) {
|
||||
const db = context.getAppDB()
|
||||
const viewName = decodeURIComponent(ctx.params.viewName)
|
||||
const view = await deleteView(viewName)
|
||||
|
@ -123,7 +130,7 @@ export async function destroy(ctx: BBContext) {
|
|||
ctx.body = view
|
||||
}
|
||||
|
||||
export async function exportView(ctx: BBContext) {
|
||||
export async function exportView(ctx: Ctx) {
|
||||
const viewName = decodeURIComponent(ctx.query.view as string)
|
||||
const view = await getView(viewName)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ type ViewTemplateOpts = {
|
|||
groupBy: string
|
||||
filters: ViewFilter[]
|
||||
calculation: string
|
||||
groupByMulti: boolean
|
||||
}
|
||||
|
||||
const TOKEN_MAP: Record<string, string> = {
|
||||
|
@ -41,6 +42,12 @@ const GROUP_PROPERTY: Record<string, { type: string }> = {
|
|||
},
|
||||
}
|
||||
|
||||
const GROUP_PROPERTY_MULTI: Record<string, { type: string }> = {
|
||||
group: {
|
||||
type: "array",
|
||||
},
|
||||
}
|
||||
|
||||
const FIELD_PROPERTY: Record<string, { type: string }> = {
|
||||
field: {
|
||||
type: "string",
|
||||
|
@ -136,13 +143,10 @@ function parseEmitExpression(field: string, groupBy: string) {
|
|||
* filters: Array of filter objects containing predicates that are parsed into a JS expression
|
||||
* calculation: an optional calculation to be performed over the view data.
|
||||
*/
|
||||
export default function ({
|
||||
field,
|
||||
tableId,
|
||||
groupBy,
|
||||
filters = [],
|
||||
calculation,
|
||||
}: ViewTemplateOpts) {
|
||||
export default function (
|
||||
{ field, tableId, groupBy, filters = [], calculation }: ViewTemplateOpts,
|
||||
groupByMulti?: boolean
|
||||
) {
|
||||
// first filter can't have a conjunction
|
||||
if (filters && filters.length > 0 && filters[0].conjunction) {
|
||||
delete filters[0].conjunction
|
||||
|
@ -151,9 +155,11 @@ export default function ({
|
|||
let schema = null,
|
||||
statFilter = null
|
||||
|
||||
let groupBySchema = groupByMulti ? GROUP_PROPERTY_MULTI : GROUP_PROPERTY
|
||||
|
||||
if (calculation) {
|
||||
schema = {
|
||||
...(groupBy ? GROUP_PROPERTY : FIELD_PROPERTY),
|
||||
...(groupBy ? groupBySchema : FIELD_PROPERTY),
|
||||
...SCHEMA_MAP[calculation],
|
||||
}
|
||||
if (
|
||||
|
|
|
@ -52,6 +52,16 @@ export function cleanInputValues(inputs: Record<string, any>, schema: any) {
|
|||
}
|
||||
}
|
||||
}
|
||||
//Check if input field should be a relationship and cast to array
|
||||
for (let key in inputs.row) {
|
||||
if (
|
||||
inputs.schema?.[key]?.type === "link" &&
|
||||
inputs.row[key] &&
|
||||
typeof inputs.row[key] === "string"
|
||||
) {
|
||||
inputs.row[key] = JSON.parse(inputs.row[key])
|
||||
}
|
||||
}
|
||||
return inputs
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ export const definition: AutomationStepSchema = {
|
|||
schema: {
|
||||
inputs: {
|
||||
properties: {
|
||||
meta: {
|
||||
type: "object",
|
||||
title: "Field settings",
|
||||
},
|
||||
row: {
|
||||
type: "object",
|
||||
customType: "row",
|
||||
|
@ -73,7 +77,10 @@ export async function run({ inputs, appId, emitter }: AutomationStepInput) {
|
|||
|
||||
// clear any undefined, null or empty string properties so that they aren't updated
|
||||
for (let propKey of Object.keys(inputs.row)) {
|
||||
if (inputs.row[propKey] == null || inputs.row[propKey] === "") {
|
||||
if (
|
||||
(inputs.row[propKey] == null || inputs.row[propKey] === "") &&
|
||||
!inputs.meta?.fields?.[propKey]?.clearRelationships
|
||||
) {
|
||||
delete inputs.row[propKey]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,6 @@ const MIN_ISO_DATE = "0000-00-00T00:00:00.000Z"
|
|||
const MAX_ISO_DATE = "9999-00-00T00:00:00.000Z"
|
||||
|
||||
function likeKey(client: string, key: string): string {
|
||||
if (!key.includes(" ")) {
|
||||
return key
|
||||
}
|
||||
let start: string, end: string
|
||||
switch (client) {
|
||||
case SqlClient.MY_SQL:
|
||||
|
@ -235,7 +232,9 @@ class InternalBuilder {
|
|||
} else {
|
||||
const rawFnc = `${fnc}Raw`
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](`LOWER(${key}) LIKE ?`, [`${value}%`])
|
||||
query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [
|
||||
`${value}%`,
|
||||
])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -147,7 +147,8 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
|
|||
if (
|
||||
field.type == "DATETIME" ||
|
||||
field.type === "DATE" ||
|
||||
field.type === "TIMESTAMP"
|
||||
field.type === "TIMESTAMP" ||
|
||||
field.type === "LONGLONG"
|
||||
) {
|
||||
return field.string()
|
||||
}
|
||||
|
|
|
@ -352,7 +352,7 @@ describe("SQL query builder", () => {
|
|||
)
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER(${TABLE_NAME}.age) LIKE @p1 AND LOWER(${TABLE_NAME}.age) LIKE @p2) and (LOWER(${TABLE_NAME}.name) LIKE @p3 AND LOWER(${TABLE_NAME}.name) LIKE @p4)) as [${TABLE_NAME}]`,
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER([${TABLE_NAME}].[age]) LIKE @p1 AND LOWER([${TABLE_NAME}].[age]) LIKE @p2) and (LOWER([${TABLE_NAME}].[name]) LIKE @p3 AND LOWER([${TABLE_NAME}].[name]) LIKE @p4)) as [${TABLE_NAME}]`,
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -403,7 +403,7 @@ describe("SQL query builder", () => {
|
|||
)
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", `%"John"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where NOT (LOWER(${TABLE_NAME}.age) LIKE @p1) and NOT (LOWER(${TABLE_NAME}.name) LIKE @p2)) as [${TABLE_NAME}]`,
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where NOT (LOWER([${TABLE_NAME}].[age]) LIKE @p1) and NOT (LOWER([${TABLE_NAME}].[name]) LIKE @p2)) as [${TABLE_NAME}]`,
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -454,7 +454,7 @@ describe("SQL query builder", () => {
|
|||
)
|
||||
expect(query).toEqual({
|
||||
bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`],
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER(${TABLE_NAME}.age) LIKE @p1 OR LOWER(${TABLE_NAME}.age) LIKE @p2) and (LOWER(${TABLE_NAME}.name) LIKE @p3 OR LOWER(${TABLE_NAME}.name) LIKE @p4)) as [${TABLE_NAME}]`,
|
||||
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER([${TABLE_NAME}].[age]) LIKE @p1 OR LOWER([${TABLE_NAME}].[age]) LIKE @p2) and (LOWER([${TABLE_NAME}].[name]) LIKE @p3 OR LOWER([${TABLE_NAME}].[name]) LIKE @p4)) as [${TABLE_NAME}]`,
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -517,4 +517,40 @@ describe("SQL query builder", () => {
|
|||
sql: `select "stores"."store_id" as "stores.store_id", "stores"."store_name" as "stores.store_name", "products"."product_id" as "products.product_id", "products"."product_name" as "products.product_name" from (select * from "production"."stores" limit $1) as "stores" left join "production"."stocks" on "stores"."store_id" = "stocks"."store_id" left join "production"."products" on "products"."product_id" = "stocks"."product_id" limit $2`,
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle table names with dashes when performing a LIKE in MySQL", () => {
|
||||
const tableName = "Table-Name-With-Dashes"
|
||||
const query = new Sql(SqlClient.MY_SQL, limit)._query(
|
||||
generateReadJson({
|
||||
table: tableName,
|
||||
filters: {
|
||||
string: {
|
||||
name: "John",
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
expect(query).toEqual({
|
||||
bindings: ["John%", limit],
|
||||
sql: `select * from (select * from \`${tableName}\` where LOWER(\`${tableName}\`.\`name\`) LIKE ? limit ?) as \`${tableName}\``,
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle table names with dashes when performing a LIKE in SQL Server", () => {
|
||||
const tableName = "Table-Name-With-Dashes"
|
||||
const query = new Sql(SqlClient.MS_SQL, limit)._query(
|
||||
generateReadJson({
|
||||
table: tableName,
|
||||
filters: {
|
||||
string: {
|
||||
name: "John",
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
expect(query).toEqual({
|
||||
bindings: [limit, "John%"],
|
||||
sql: `select * from (select top (@p0) * from [${tableName}] where LOWER([${tableName}].[name]) LIKE @p1) as [${tableName}]`,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -8,7 +8,6 @@ const ROW_ID_REGEX = /^\[.*]$/g
|
|||
const SQL_NUMBER_TYPE_MAP = {
|
||||
integer: FieldTypes.NUMBER,
|
||||
int: FieldTypes.NUMBER,
|
||||
bigint: FieldTypes.NUMBER,
|
||||
decimal: FieldTypes.NUMBER,
|
||||
smallint: FieldTypes.NUMBER,
|
||||
real: FieldTypes.NUMBER,
|
||||
|
@ -47,6 +46,7 @@ const SQL_STRING_TYPE_MAP = {
|
|||
blob: FieldTypes.STRING,
|
||||
long: FieldTypes.STRING,
|
||||
text: FieldTypes.STRING,
|
||||
bigint: FieldTypes.STRING,
|
||||
}
|
||||
|
||||
const SQL_BOOLEAN_TYPE_MAP = {
|
||||
|
@ -141,12 +141,18 @@ export function breakRowIdField(_id: string | { _id: string }): any[] {
|
|||
export function convertSqlType(type: string) {
|
||||
let foundType = FieldTypes.STRING
|
||||
const lcType = type.toLowerCase()
|
||||
let matchingTypes = []
|
||||
for (let [external, internal] of Object.entries(SQL_TYPE_MAP)) {
|
||||
if (lcType.includes(external)) {
|
||||
foundType = internal
|
||||
break
|
||||
matchingTypes.push({ external, internal })
|
||||
}
|
||||
}
|
||||
//Set the foundType based the longest match
|
||||
if (matchingTypes.length > 0) {
|
||||
foundType = matchingTypes.reduce((acc, val) => {
|
||||
return acc.external.length >= val.external.length ? acc : val
|
||||
}).internal
|
||||
}
|
||||
const schema: any = { type: foundType }
|
||||
if (foundType === FieldTypes.DATETIME) {
|
||||
schema.dateOnly = SQL_DATE_ONLY_TYPES.includes(lcType)
|
||||
|
|
|
@ -91,7 +91,7 @@ class QueryRunner {
|
|||
let query
|
||||
// handle SQL injections by interpolating the variables
|
||||
if (isSQL(datasourceClone)) {
|
||||
query = await interpolateSQL(fieldsClone, enrichedParameters, integration)
|
||||
query = await interpolateSQL(fieldsClone, enrichedContext, integration)
|
||||
} else {
|
||||
query = await sdk.queries.enrichContext(fieldsClone, enrichedContext)
|
||||
}
|
||||
|
|
|
@ -1273,13 +1273,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.2.12-alpha.71.tgz#bd61a9158ed601d7860e6fa9afaf233217944dd3"
|
||||
integrity sha512-QDhBsiqTrWFhXZMaotLpt4+StKDGTL/HzTm0kwTgAAkvsA2tkkiCZCjx2fOsdpYBvTfJ0vN+h4Kg6gKDY3I7NA==
|
||||
"@budibase/backend-core@2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.0.tgz#fb40b77db6ae655e527aa43467e5a9145522bb44"
|
||||
integrity sha512-Qvt9Tr6em6KPUhnj16jggcGR1l9b2qaOcrzoDfzCbSRcZcHuQ8mBHYvdHqlGyH6rHbJCsDrz8/KqNT8qRc2IyQ==
|
||||
dependencies:
|
||||
"@budibase/nano" "10.1.1"
|
||||
"@budibase/types" "2.2.12-alpha.71"
|
||||
"@budibase/types" "^2.3.0"
|
||||
"@shopify/jest-koa-mocks" "5.0.1"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-cloudfront-sign "2.2.0"
|
||||
|
@ -1374,13 +1374,13 @@
|
|||
qs "^6.11.0"
|
||||
tough-cookie "^4.1.2"
|
||||
|
||||
"@budibase/pro@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.2.12-alpha.71.tgz#c1272a512c0ab5d4252c175d91ebbc69bb1596e0"
|
||||
integrity sha512-qZP0RLzZ08nvDPwmIxbRgHI/C/jgjMlx8liiOU6/RhL6c9HT1Rxa3ABSpBxmQvLu5OrxUgC8cJY1cJ7v9LD8MQ==
|
||||
"@budibase/pro@2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.0.tgz#adc43a2132025593b9da2ad9449a82c5196f7216"
|
||||
integrity sha512-hfjcncN/g6fTxmQHiXXf1oPeo2oB5XUi17xju7LVnQEDwmyrtW3rbrCuvCQpYQII1C3nsuFsakanXLpCouLCGA==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "2.2.12-alpha.71"
|
||||
"@budibase/types" "2.2.12-alpha.71"
|
||||
"@budibase/backend-core" "2.3.0"
|
||||
"@budibase/types" "2.3.0"
|
||||
"@koa/router" "8.0.8"
|
||||
bull "4.10.1"
|
||||
joi "17.6.0"
|
||||
|
@ -1406,10 +1406,10 @@
|
|||
svelte-apexcharts "^1.0.2"
|
||||
svelte-flatpickr "^3.1.0"
|
||||
|
||||
"@budibase/types@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.2.12-alpha.71.tgz#ba8c1e8bb6945a6b9cebc0ae03c61a51b6e9a6f7"
|
||||
integrity sha512-JdtZ0AxoyTIAnJpnh17Yb0VgaNk6xEHy/Fb6AbSMQ0tAvAFK1xbVdJhvpyxbyFqOpB6ZxlV7ekE3VfOrR0YQRA==
|
||||
"@budibase/types@2.3.0", "@budibase/types@^2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.0.tgz#ab5ce3451ac0ad3a3cfb5846228e820d4f597b28"
|
||||
integrity sha512-rTLXoCElUOG+EMD/qbrUyGwXk5cwatOFtylyI01pYIyM7HS/Hy0YekLJVcWQKOf2PGTcYah3AdtkYSIYaZDSfA==
|
||||
|
||||
"@bull-board/api@3.7.0":
|
||||
version "3.7.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.2.12-alpha.71",
|
||||
"version": "2.3.0",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -36,10 +36,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.2.12-alpha.71",
|
||||
"@budibase/pro": "2.2.12-alpha.71",
|
||||
"@budibase/string-templates": "2.2.12-alpha.71",
|
||||
"@budibase/types": "2.2.12-alpha.71",
|
||||
"@budibase/backend-core": "^2.3.0",
|
||||
"@budibase/pro": "2.3.0",
|
||||
"@budibase/string-templates": "^2.3.0",
|
||||
"@budibase/types": "^2.3.0",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -470,13 +470,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.2.12-alpha.71.tgz#bd61a9158ed601d7860e6fa9afaf233217944dd3"
|
||||
integrity sha512-QDhBsiqTrWFhXZMaotLpt4+StKDGTL/HzTm0kwTgAAkvsA2tkkiCZCjx2fOsdpYBvTfJ0vN+h4Kg6gKDY3I7NA==
|
||||
"@budibase/backend-core@2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.0.tgz#fb40b77db6ae655e527aa43467e5a9145522bb44"
|
||||
integrity sha512-Qvt9Tr6em6KPUhnj16jggcGR1l9b2qaOcrzoDfzCbSRcZcHuQ8mBHYvdHqlGyH6rHbJCsDrz8/KqNT8qRc2IyQ==
|
||||
dependencies:
|
||||
"@budibase/nano" "10.1.1"
|
||||
"@budibase/types" "2.2.12-alpha.71"
|
||||
"@budibase/types" "^2.3.0"
|
||||
"@shopify/jest-koa-mocks" "5.0.1"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-cloudfront-sign "2.2.0"
|
||||
|
@ -521,13 +521,13 @@
|
|||
qs "^6.11.0"
|
||||
tough-cookie "^4.1.2"
|
||||
|
||||
"@budibase/pro@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.2.12-alpha.71.tgz#c1272a512c0ab5d4252c175d91ebbc69bb1596e0"
|
||||
integrity sha512-qZP0RLzZ08nvDPwmIxbRgHI/C/jgjMlx8liiOU6/RhL6c9HT1Rxa3ABSpBxmQvLu5OrxUgC8cJY1cJ7v9LD8MQ==
|
||||
"@budibase/pro@2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.0.tgz#adc43a2132025593b9da2ad9449a82c5196f7216"
|
||||
integrity sha512-hfjcncN/g6fTxmQHiXXf1oPeo2oB5XUi17xju7LVnQEDwmyrtW3rbrCuvCQpYQII1C3nsuFsakanXLpCouLCGA==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "2.2.12-alpha.71"
|
||||
"@budibase/types" "2.2.12-alpha.71"
|
||||
"@budibase/backend-core" "2.3.0"
|
||||
"@budibase/types" "2.3.0"
|
||||
"@koa/router" "8.0.8"
|
||||
bull "4.10.1"
|
||||
joi "17.6.0"
|
||||
|
@ -535,10 +535,10 @@
|
|||
lru-cache "^7.14.1"
|
||||
node-fetch "^2.6.1"
|
||||
|
||||
"@budibase/types@2.2.12-alpha.71":
|
||||
version "2.2.12-alpha.71"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.2.12-alpha.71.tgz#ba8c1e8bb6945a6b9cebc0ae03c61a51b6e9a6f7"
|
||||
integrity sha512-JdtZ0AxoyTIAnJpnh17Yb0VgaNk6xEHy/Fb6AbSMQ0tAvAFK1xbVdJhvpyxbyFqOpB6ZxlV7ekE3VfOrR0YQRA==
|
||||
"@budibase/types@2.3.0", "@budibase/types@^2.3.0":
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.0.tgz#ab5ce3451ac0ad3a3cfb5846228e820d4f597b28"
|
||||
integrity sha512-rTLXoCElUOG+EMD/qbrUyGwXk5cwatOFtylyI01pYIyM7HS/Hy0YekLJVcWQKOf2PGTcYah3AdtkYSIYaZDSfA==
|
||||
|
||||
"@cspotcode/source-map-support@^0.8.0":
|
||||
version "0.8.1"
|
||||
|
|
Loading…
Reference in New Issue