Skip to content

Commit

Permalink
Merge pull request Budibase#11782 from Budibase/feature/user-column-type
Browse files Browse the repository at this point in the history
Feature - User column type
  • Loading branch information
adrinr authored Sep 26, 2023
2 parents 48396ca + 0bc972a commit ab9df22
Show file tree
Hide file tree
Showing 36 changed files with 930 additions and 68 deletions.
2 changes: 1 addition & 1 deletion packages/backend-core/src/cache/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export async function getUsers(
): Promise<{ users: User[]; notFoundIds?: string[] }> {
const client = await redis.getUserClient()
// try cache
let usersFromCache = await client.bulkGet(userIds)
let usersFromCache = await client.bulkGet<User>(userIds)
const missingUsersFromCache = userIds.filter(uid => !usersFromCache[uid])
const users = Object.values(usersFromCache)
let notFoundIds
Expand Down
4 changes: 2 additions & 2 deletions packages/backend-core/src/redis/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,15 +242,15 @@ class RedisWrapper {
}
}

async bulkGet(keys: string[]) {
async bulkGet<T>(keys: string[]) {
const db = this._db
if (keys.length === 0) {
return {}
}
const prefixedKeys = keys.map(key => addDbPrefix(db, key))
let response = await this.getClient().mget(prefixedKeys)
if (Array.isArray(response)) {
let final: Record<string, any> = {}
let final: Record<string, T> = {}
let count = 0
for (let result of response) {
if (result) {
Expand Down
2 changes: 1 addition & 1 deletion packages/backend-core/tests/extra/DBTestConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class DBTestConfiguration {

// TENANCY

doInTenant(task: any) {
doInTenant<T>(task: () => Promise<T>) {
return context.doInTenant(this.tenantId, () => {
return task()
})
Expand Down
1 change: 1 addition & 0 deletions packages/backend-core/tests/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./core/utilities"
export * from "./extra"
1 change: 1 addition & 0 deletions packages/bbui/src/Table/CellRenderer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
longform: StringRenderer,
array: ArrayRenderer,
internal: InternalRenderer,
bb_reference: RelationshipRenderer,
}
$: type = getType(schema)
$: customRenderer = customRenderers?.find(x => x.column === schema?.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import { getBindings } from "components/backend/DataTable/formula"
import JSONSchemaModal from "./JSONSchemaModal.svelte"
import { ValidColumnNameRegex } from "@budibase/shared-core"
import { FieldSubtype, FieldType } from "@budibase/types"
import RelationshipSelector from "components/common/RelationshipSelector.svelte"
const AUTO_TYPE = "auto"
Expand All @@ -42,6 +43,11 @@
const NUMBER_TYPE = FIELDS.NUMBER.type
const JSON_TYPE = FIELDS.JSON.type
const DATE_TYPE = FIELDS.DATETIME.type
const BB_REFERENCE_TYPE = FieldType.BB_REFERENCE
const BB_USER_REFERENCE_TYPE = composeType(
BB_REFERENCE_TYPE,
FieldSubtype.USER
)
const dispatch = createEventDispatcher()
const PROHIBITED_COLUMN_NAMES = ["type", "_id", "_rev", "tableId"]
Expand All @@ -68,12 +74,39 @@
let jsonSchemaModal
let allowedTypes = []
let editableColumn = {
type: "string",
type: fieldDefinitions.STRING.type,
constraints: fieldDefinitions.STRING.constraints,
// Initial value for column name in other table for linked records
fieldName: $tables.selected.name,
}
const bbRefTypeMapping = {}
function composeType(fieldType, subtype) {
return `${fieldType}_${subtype}`
}
// Handling fields with subtypes
fieldDefinitions = Object.entries(fieldDefinitions).reduce(
(p, [key, field]) => {
if (field.type === BB_REFERENCE_TYPE) {
const composedType = composeType(field.type, field.subtype)
p[key] = {
...field,
type: composedType,
}
bbRefTypeMapping[composedType] = {
type: field.type,
subtype: field.subtype,
}
} else {
p[key] = field
}
return p
},
{}
)
$: if (primaryDisplay) {
editableColumn.constraints.presence = { allowEmpty: false }
}
Expand Down Expand Up @@ -107,13 +140,22 @@
const initialiseField = (field, savingColumn) => {
isCreating = !field
if (field && !savingColumn) {
editableColumn = cloneDeep(field)
originalName = editableColumn.name ? editableColumn.name + "" : null
linkEditDisabled = originalName != null
primaryDisplay =
$tables.selected.primaryDisplay == null ||
$tables.selected.primaryDisplay === editableColumn.name
const mapped = Object.entries(bbRefTypeMapping).find(
([_, v]) => v.type === field.type && v.subtype === field.subtype
)
if (mapped) {
editableColumn.type = mapped[0]
delete editableColumn.subtype
}
} else if (!savingColumn) {
let highestNumber = 0
Object.keys(table.schema).forEach(columnName => {
Expand All @@ -130,6 +172,7 @@
editableColumn.name = "Column 01"
}
}
allowedTypes = getAllowedTypes()
if (editableColumn.type === LINK_TYPE && editableColumn.tableId) {
Expand All @@ -145,6 +188,8 @@
$: initialiseField(field, savingColumn)
$: isBBReference = !!bbRefTypeMapping[editableColumn.type]
$: checkConstraints(editableColumn)
$: required = !!editableColumn?.constraints?.presence || primaryDisplay
$: uneditable =
Expand Down Expand Up @@ -220,6 +265,13 @@
let saveColumn = cloneDeep(editableColumn)
if (bbRefTypeMapping[saveColumn.type]) {
saveColumn = {
...saveColumn,
...bbRefTypeMapping[saveColumn.type],
}
}
if (saveColumn.type === AUTO_TYPE) {
saveColumn = buildAutoColumn(
$tables.selected.name,
Expand Down Expand Up @@ -298,9 +350,10 @@
// Default relationships many to many
if (editableColumn.type === LINK_TYPE) {
editableColumn.relationshipType = RelationshipType.MANY_TO_MANY
}
if (editableColumn.type === FORMULA_TYPE) {
} else if (editableColumn.type === FORMULA_TYPE) {
editableColumn.formulaType = "dynamic"
} else if (editableColumn.type === BB_USER_REFERENCE_TYPE) {
editableColumn.relationshipType = RelationshipType.ONE_TO_MANY
}
}
Expand Down Expand Up @@ -339,7 +392,9 @@
ALLOWABLE_NUMBER_TYPES.indexOf(editableColumn.type) !== -1
) {
return ALLOWABLE_NUMBER_OPTIONS
} else if (!external) {
}
if (!external) {
return [
...Object.values(fieldDefinitions),
{ name: "Auto Column", type: AUTO_TYPE },
Expand All @@ -360,6 +415,9 @@
if (!external || table.sql) {
fields = [...fields, FIELDS.LINK, FIELDS.ARRAY]
}
if (fieldDefinitions.USER) {
fields.push(fieldDefinitions.USER)
}
return fields
}
}
Expand Down Expand Up @@ -613,6 +671,17 @@
<Button primary text on:click={openJsonSchemaEditor}
>Open schema editor</Button
>
{:else if isBBReference}
<Toggle
value={editableColumn.relationshipType === RelationshipType.MANY_TO_MANY}
on:change={e =>
(editableColumn.relationshipType = e.detail
? RelationshipType.MANY_TO_MANY
: RelationshipType.ONE_TO_MANY)}
disabled={!isCreating}
thin
text="Allow multiple users"
/>
{/if}
{#if editableColumn.type === AUTO_TYPE || editableColumn.autocolumn}
<Select
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const componentMap = {
"field/array": FormFieldSelect,
"field/json": FormFieldSelect,
"field/barcodeqr": FormFieldSelect,
"field/bb_reference": FormFieldSelect,
// Some validation types are the same as others, so not all types are
// explicitly listed here. e.g. options uses string validation
"validation/string": ValidationEditor,
Expand All @@ -74,6 +75,7 @@ const componentMap = {
"validation/datetime": ValidationEditor,
"validation/attachment": ValidationEditor,
"validation/link": ValidationEditor,
"validation/bb_reference": ValidationEditor,
}

export const getComponentForSetting = setting => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export const FieldTypeToComponentMap = {
link: "relationshipfield",
json: "jsonfield",
barcodeqr: "codescanner",
bb_reference: "bbreferencefield",
}
6 changes: 6 additions & 0 deletions packages/builder/src/constants/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ export const FIELDS = {
presence: false,
},
},
USER: {
name: "User",
type: "bb_reference",
subtype: "user",
icon: "User",
},
}

export const AUTO_COLUMN_SUB_TYPES = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
"datetimefield",
"multifieldselect",
"s3upload",
"codescanner"
"codescanner",
"bbreferencefield"
]
},
{
Expand Down
68 changes: 68 additions & 0 deletions packages/client/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5623,5 +5623,73 @@
"defaultValue": false
}
]
},
"bbreferencefield": {
"devComment": "As bb reference is only used for user subtype for now, we are using user for icon and labels",
"name": "User Field",
"icon": "User",
"styles": ["size"],
"requiredAncestors": ["form"],
"editable": true,
"size": {
"width": 400,
"height": 50
},
"settings": [
{
"type": "field/bb_reference",
"label": "Field",
"key": "field",
"required": true
},
{
"type": "text",
"label": "Label",
"key": "label"
},
{
"type": "text",
"label": "Placeholder",
"key": "placeholder"
},
{
"type": "text",
"label": "Default value",
"key": "defaultValue"
},
{
"type": "event",
"label": "On change",
"key": "onChange",
"context": [
{
"label": "Field Value",
"key": "value"
}
]
},
{
"type": "validation/link",
"label": "Validation",
"key": "validation"
},
{
"type": "filter/relationship",
"label": "Filtering",
"key": "filter"
},
{
"type": "boolean",
"label": "Search",
"key": "autocomplete",
"defaultValue": true
},
{
"type": "boolean",
"label": "Disabled",
"key": "disabled",
"defaultValue": false
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
link: "relationshipfield",
json: "jsonfield",
barcodeqr: "codescanner",
bb_reference: "bbreferencefield",
}
let formId
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import RelationshipField from "./RelationshipField.svelte"
</script>

<RelationshipField
{...$$props}
datasourceType={"user"}
primaryDisplay={"email"}
/>
Loading

0 comments on commit ab9df22

Please sign in to comment.