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