Merge branch 'develop' into feature/user-column-type

This commit is contained in:
Adria Navarro 2023-09-26 11:51:20 +02:00 committed by GitHub
commit f4542283f5
10 changed files with 160 additions and 67 deletions

View File

@ -0,0 +1,21 @@
name: close-featurebranch
on:
pull_request:
types: [closed]
branches:
- develop
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: passeidireto/trigger-external-workflow-action@main
env:
PAYLOAD_BRANCH: ${{ github.head_ref }}
PAYLOAD_PR_NUMBER: ${{ github.ref }}
with:
repository: budibase/budibase-deploys
event: featurebranch-qa-close
github_pat: ${{ secrets.GH_ACCESS_TOKEN }}

View File

@ -1,5 +1,5 @@
{ {
"version": "2.10.12-alpha.14", "version": "2.10.12-alpha.19",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -96,8 +96,8 @@
{disabled} {disabled}
{readonly} {readonly}
{id} {id}
value={value || ""} value={value ?? ""}
placeholder={placeholder || ""} placeholder={placeholder ?? ""}
on:click on:click
on:blur on:blur
on:focus on:focus

View File

@ -2,6 +2,7 @@ export const Events = {
COMPONENT_CREATED: "component:created", COMPONENT_CREATED: "component:created",
COMPONENT_UPDATED: "component:updated", COMPONENT_UPDATED: "component:updated",
APP_VIEW_PUBLISHED: "app:view_published", APP_VIEW_PUBLISHED: "app:view_published",
BLOCK_EJECTED: "block:ejected",
} }
export const EventSource = { export const EventSource = {

View File

@ -1287,6 +1287,11 @@ export const getFrontendStore = () => {
return false return false
} }
// Log event
analytics.captureEvent(Events.BLOCK_EJECTED, {
block: block._component,
})
// Attach block children back into ejected definition, using the // Attach block children back into ejected definition, using the
// _containsSlot flag to know where to insert them // _containsSlot flag to know where to insert them
const slotContainer = findAllMatchingComponents( const slotContainer = findAllMatchingComponents(

View File

@ -5,7 +5,6 @@
Label, Label,
Select, Select,
Toggle, Toggle,
RadioGroup,
Icon, Icon,
DatePicker, DatePicker,
Modal, Modal,
@ -26,16 +25,17 @@
ALLOWABLE_STRING_TYPES, ALLOWABLE_STRING_TYPES,
ALLOWABLE_NUMBER_TYPES, ALLOWABLE_NUMBER_TYPES,
SWITCHABLE_TYPES, SWITCHABLE_TYPES,
PrettyRelationshipDefinitions,
} from "constants/backend" } from "constants/backend"
import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils" import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { truncate } from "lodash"
import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte" import ModalBindableInput from "components/common/bindings/ModalBindableInput.svelte"
import { getBindings } from "components/backend/DataTable/formula" import { getBindings } from "components/backend/DataTable/formula"
import JSONSchemaModal from "./JSONSchemaModal.svelte" import JSONSchemaModal from "./JSONSchemaModal.svelte"
import { ValidColumnNameRegex } from "@budibase/shared-core" import { ValidColumnNameRegex } from "@budibase/shared-core"
import { admin } from "stores/portal" import { admin } from "stores/portal"
import { FieldSubtype, FieldType } from "@budibase/types" import { FieldSubtype, FieldType } from "@budibase/types"
import RelationshipSelector from "components/common/RelationshipSelector.svelte"
const AUTO_TYPE = "auto" const AUTO_TYPE = "auto"
const FORMULA_TYPE = FIELDS.FORMULA.type const FORMULA_TYPE = FIELDS.FORMULA.type
@ -64,6 +64,10 @@
let indexes = [...($tables.selected.indexes || [])] let indexes = [...($tables.selected.indexes || [])]
let isCreating = undefined let isCreating = undefined
let relationshipPart1 = PrettyRelationshipDefinitions.Many
let relationshipPart2 = PrettyRelationshipDefinitions.One
let relationshipTableIdSecondary = null
let table = $tables.selected let table = $tables.selected
let confirmDeleteDialog let confirmDeleteDialog
let savingColumn let savingColumn
@ -111,6 +115,33 @@
editableColumn.constraints.presence = { allowEmpty: false } editableColumn.constraints.presence = { allowEmpty: false }
} }
let relationshipMap = {
[RelationshipType.MANY_TO_ONE]: {
part1: PrettyRelationshipDefinitions.MANY,
part2: PrettyRelationshipDefinitions.ONE,
},
[RelationshipType.MANY_TO_MANY]: {
part1: PrettyRelationshipDefinitions.MANY,
part2: PrettyRelationshipDefinitions.MANY,
},
[RelationshipType.ONE_TO_MANY]: {
part1: PrettyRelationshipDefinitions.ONE,
part2: PrettyRelationshipDefinitions.MANY,
},
}
$: {
if (editableColumn.type === LINK_TYPE) {
// Determine the relationship type based on the selected values of both parts
editableColumn.relationshipType = Object.entries(relationshipMap).find(
([_, parts]) =>
parts.part1 === relationshipPart1 && parts.part2 === relationshipPart2
)?.[0]
// Set the tableId based on the selected table
editableColumn.tableId = relationshipTableIdSecondary
}
}
const initialiseField = (field, savingColumn) => { const initialiseField = (field, savingColumn) => {
isCreating = !field isCreating = !field
@ -147,6 +178,16 @@
} }
allowedTypes = getAllowedTypes() allowedTypes = getAllowedTypes()
if (editableColumn.type === LINK_TYPE && editableColumn.tableId) {
relationshipTableIdSecondary = editableColumn.tableId
if (editableColumn.relationshipType in relationshipMap) {
const { part1, part2 } =
relationshipMap[editableColumn.relationshipType]
relationshipPart1 = part1
relationshipPart2 = part2
}
}
} }
$: initialiseField(field, savingColumn) $: initialiseField(field, savingColumn)
@ -206,7 +247,6 @@
!uneditable && !uneditable &&
editableColumn?.type !== AUTO_TYPE && editableColumn?.type !== AUTO_TYPE &&
!editableColumn.autocolumn !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(
@ -345,35 +385,6 @@
return match ? parseInt(match[1]) : 0 return match ? parseInt(match[1]) : 0
} }
function getRelationshipOptions(field) {
if (!field || !field.tableId) {
return null
}
const linkTable = tableOptions?.find(table => table._id === field.tableId)
if (!linkTable) {
return null
}
const thisName = truncate(table.name, { length: 14 }),
linkName = truncate(linkTable.name, { length: 14 })
return [
{
name: `Many ${thisName} rows → many ${linkName} rows`,
alt: `Many ${table.name} rows → many ${linkTable.name} rows`,
value: RelationshipType.MANY_TO_MANY,
},
{
name: `One ${linkName} row → many ${thisName} rows`,
alt: `One ${linkTable.name} rows → many ${table.name} rows`,
value: RelationshipType.ONE_TO_MANY,
},
{
name: `One ${thisName} row → many ${linkName} rows`,
alt: `One ${table.name} rows → many ${linkTable.name} rows`,
value: RelationshipType.MANY_TO_ONE,
},
]
}
function getAllowedTypes() { function getAllowedTypes() {
if ( if (
originalName && originalName &&
@ -562,7 +573,7 @@
<DatePicker bind:value={editableColumn.constraints.datetime.latest} /> <DatePicker bind:value={editableColumn.constraints.datetime.latest} />
</div> </div>
</div> </div>
{#if datasource?.source !== "ORACLE" && datasource?.source !== "SQL_SERVER"} {#if datasource?.source !== "ORACLE" && datasource?.source !== "SQL_SERVER" && !editableColumn.dateOnly}
<div> <div>
<div class="row"> <div class="row">
<Label>Time zones</Label> <Label>Time zones</Label>
@ -582,6 +593,7 @@
/> />
</div> </div>
{/if} {/if}
<Toggle bind:value={editableColumn.dateOnly} text="Date only" />
{:else if editableColumn.type === "number" && !editableColumn.autocolumn} {:else if editableColumn.type === "number" && !editableColumn.autocolumn}
<div class="split-label"> <div class="split-label">
<div class="label-length"> <div class="label-length">
@ -608,30 +620,15 @@
</div> </div>
</div> </div>
{:else if editableColumn.type === "link"} {:else if editableColumn.type === "link"}
<Select <RelationshipSelector
label="Table" bind:relationshipPart1
disabled={linkEditDisabled} bind:relationshipPart2
bind:value={editableColumn.tableId} bind:relationshipTableIdPrimary={table.name}
options={tableOptions} bind:relationshipTableIdSecondary
getOptionLabel={table => table.name} bind:editableColumn
getOptionValue={table => table._id} {linkEditDisabled}
/> {tableOptions}
{#if relationshipOptions && relationshipOptions.length > 0} {errors}
<RadioGroup
disabled={linkEditDisabled}
label="Define the relationship"
bind:value={editableColumn.relationshipType}
options={relationshipOptions}
getOptionLabel={option => option.name}
getOptionValue={option => option.value}
getOptionTitle={option => option.alt}
/>
{/if}
<Input
disabled={linkEditDisabled}
label={`Column name in other table`}
bind:value={editableColumn.fieldName}
error={errors.relatedName}
/> />
{:else if editableColumn.type === FORMULA_TYPE} {:else if editableColumn.type === FORMULA_TYPE}
{#if !table.sql} {#if !table.sql}

View File

@ -0,0 +1,69 @@
<script>
import { Select, Input } from "@budibase/bbui"
import { PrettyRelationshipDefinitions } from "constants/backend"
export let relationshipPart1
export let relationshipPart2
export let relationshipTableIdPrimary
export let relationshipTableIdSecondary
export let editableColumn
export let linkEditDisabled
export let tableOptions
export let errors
</script>
<div class="relationship-container">
<div class="relationship-part">
<Select
disabled={linkEditDisabled}
bind:value={relationshipPart1}
options={Object.values(PrettyRelationshipDefinitions)}
/>
</div>
<div class="relationship-label">in</div>
<div class="relationship-part">
<Select
disabled
options={[relationshipTableIdPrimary]}
value={relationshipTableIdPrimary}
/>
</div>
</div>
<div class="relationship-container">
<div class="relationship-part">
<Select
disabled={linkEditDisabled}
bind:value={relationshipPart2}
options={Object.values(PrettyRelationshipDefinitions)}
getOptionLabel={option => "To " + option.toLowerCase()}
/>
</div>
<div class="relationship-label">in</div>
<div class="relationship-part">
<Select
disabled={linkEditDisabled}
bind:value={relationshipTableIdSecondary}
options={tableOptions}
getOptionLabel={table => table.name}
getOptionValue={table => table._id}
/>
</div>
</div>
<Input
disabled={linkEditDisabled}
label={`Column name in other table`}
bind:value={editableColumn.fieldName}
error={errors.relatedName}
/>
<style>
.relationship-container {
display: flex;
align-items: center;
gap: 20px;
}
.relationship-part {
flex-basis: 60%;
}
</style>

View File

@ -176,6 +176,11 @@ export const RelationshipType = {
MANY_TO_ONE: "many-to-one", MANY_TO_ONE: "many-to-one",
} }
export const PrettyRelationshipDefinitions = {
MANY: "Many rows",
ONE: "One row",
}
export const ALLOWABLE_STRING_OPTIONS = [ export const ALLOWABLE_STRING_OPTIONS = [
FIELDS.STRING, FIELDS.STRING,
FIELDS.OPTIONS, FIELDS.OPTIONS,

View File

@ -45,7 +45,7 @@
on:focus={() => (active = true)} on:focus={() => (active = true)}
on:blur={() => (active = false)} on:blur={() => (active = false)}
{type} {type}
value={value || ""} value={value ?? ""}
on:change={handleChange} on:change={handleChange}
spellcheck="false" spellcheck="false"
/> />

View File

@ -305,12 +305,7 @@ export class ExternalRequest {
manyRelationships: ManyRelationship[] = [] manyRelationships: ManyRelationship[] = []
for (let [key, field] of Object.entries(table.schema)) { for (let [key, field] of Object.entries(table.schema)) {
// if set already, or not set just skip it // if set already, or not set just skip it
if (row[key] == null || newRow[key] || !isEditableColumn(field)) { if (row[key] === undefined || newRow[key] || !isEditableColumn(field)) {
continue
}
// if its an empty string then it means return the column to null (if possible)
if (row[key] === "") {
newRow[key] = null
continue continue
} }
// parse floats/numbers // parse floats/numbers