diff --git a/plugins/airtable/src/App.css b/plugins/airtable/src/App.css
index f9e9b1e8b..ad4cdd78b 100644
--- a/plugins/airtable/src/App.css
+++ b/plugins/airtable/src/App.css
@@ -12,14 +12,6 @@ form {
-webkit-user-select: none;
}
-select:disabled {
- opacity: 0.5;
-}
-
-select:not(:disabled) {
- cursor: pointer;
-}
-
.sticky-top {
position: sticky;
top: 0;
@@ -53,13 +45,6 @@ select:not(:disabled) {
border-radius: 10px;
}
-.setup-container {
- display: flex;
- flex-direction: column;
- gap: 10px;
- width: 100%;
-}
-
.setup label {
display: flex;
flex-direction: row;
@@ -81,7 +66,7 @@ select:not(:disabled) {
.mapping .fields {
display: grid;
- grid-template-columns: 1fr 8px 1fr 1fr;
+ grid-template-columns: 1fr 8px 1fr 8px 1fr;
gap: 10px;
margin-bottom: auto;
padding-bottom: 10px;
@@ -99,6 +84,10 @@ select:not(:disabled) {
color: var(--framer-color-text-tertiary);
}
+.mapping .field-type-select {
+ width: 100%;
+}
+
.mapping .source-field {
display: flex;
flex-direction: row;
@@ -127,44 +116,6 @@ select:not(:disabled) {
box-shadow: none;
}
-.mapping .unsupported-field {
- grid-column: span 2;
- background-color: var(--framer-color-bg-tertiary);
- border-radius: 8px;
- padding: 0px 10px;
- height: 30px;
- display: flex;
- flex-direction: row;
- align-items: center;
- opacity: 0.5;
- color: var(--framer-color-text-secondary);
-}
-
-.mapping .field-type-select {
- width: 100%;
-}
-
-.mapping .heading-row {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- width: 100%;
-}
-
-.mapping .heading-link {
- width: fit-content;
- max-width: 50%;
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 4px;
-}
-
-.mapping .heading-link:hover {
- text-decoration: underline;
-}
-
.mapping footer {
position: sticky;
bottom: 0;
diff --git a/plugins/airtable/src/App.tsx b/plugins/airtable/src/App.tsx
index e658ead28..54911f22c 100644
--- a/plugins/airtable/src/App.tsx
+++ b/plugins/airtable/src/App.tsx
@@ -26,8 +26,8 @@ export function App({ collection, previousBaseId, previousTableId, previousSlugF
const hasDataSourceSelected = Boolean(dataSource)
framer.showUI({
- width: hasDataSourceSelected ? 425 : 320,
- height: hasDataSourceSelected ? 425 : 345,
+ width: hasDataSourceSelected ? 360 : 320,
+ height: hasDataSourceSelected ? 425 : 350,
minWidth: hasDataSourceSelected ? 360 : undefined,
minHeight: hasDataSourceSelected ? 425 : undefined,
resizable: hasDataSourceSelected,
diff --git a/plugins/airtable/src/FieldMapping.tsx b/plugins/airtable/src/FieldMapping.tsx
index ffa1f1b28..c34051823 100644
--- a/plugins/airtable/src/FieldMapping.tsx
+++ b/plugins/airtable/src/FieldMapping.tsx
@@ -23,14 +23,14 @@ function ChevronIcon() {
}
const fieldTypeOptions: { type: Field["type"]; label: string }[] = [
- { type: "string", label: "Plain Text" },
- { type: "formattedText", label: "Formatted Text" },
- { type: "date", label: "Date" },
- { type: "link", label: "Link" },
- { type: "image", label: "Image" },
+ { type: "boolean", label: "Boolean" },
{ type: "color", label: "Color" },
- { type: "boolean", label: "Toggle" },
{ type: "number", label: "Number" },
+ { type: "string", label: "String" },
+ { type: "formattedText", label: "Formatted Text" },
+ { type: "image", label: "Image" },
+ { type: "link", label: "Link" },
+ { type: "date", label: "Date" },
{ type: "enum", label: "Option" },
{ type: "file", label: "File" },
]
@@ -40,48 +40,21 @@ interface FieldMappingRowProps {
originalFieldName: string | undefined
isIgnored: boolean
disabled: boolean
- unsupported?: boolean
- missingCollection?: boolean
onToggleIgnored?: (fieldId: string) => void
onNameChange?: (fieldId: string, name: string) => void
onTypeChange?: (fieldId: string, type: string) => void
}
-interface SelectOption {
- id: string
- label: string
-}
-
const FieldMappingRow = memo(
({
field,
originalFieldName,
isIgnored,
disabled,
- unsupported,
- missingCollection,
onToggleIgnored,
onNameChange,
onTypeChange,
}: FieldMappingRowProps) => {
- let selectOptions: SelectOption[] = []
- if (!unsupported && !missingCollection) {
- if (isCollectionReference(field)) {
- selectOptions = field.supportedCollections.map(collection => ({
- id: collection.id,
- label: collection.name,
- }))
- } else if (Array.isArray(field.allowedTypes)) {
- selectOptions = field.allowedTypes.map(type => {
- const capitalizedType = type.charAt(0).toUpperCase() + type.slice(1)
- return {
- id: type,
- label: fieldTypeOptions.find(option => option.type === type)?.label ?? capitalizedType,
- }
- })
- }
- }
-
return (
<>
- {unsupported || missingCollection ? (
-
{unsupported ? "Unsupported Field" : "Missing Collection"}
- ) : (
- <>
-
>
)
}
)
-function isFieldMissingCollection(field: PossibleField): boolean {
- return isCollectionReference(field) && field.supportedCollections.length === 0
-}
-
const initialManagedCollectionFields: PossibleField[] = []
const initialFieldIds: ReadonlySet = new Set()
@@ -234,8 +219,16 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie
return { ...field, type: "string" } as PossibleField
case "formattedText":
return { ...field, type: "formattedText" } as PossibleField
+ case "number":
+ return { ...field, type: "number" } as PossibleField
+ case "boolean":
+ return { ...field, type: "boolean" } as PossibleField
case "color":
return { ...field, type: "color" } as PossibleField
+ case "date":
+ return { ...field, type: "date" } as PossibleField
+ case "enum":
+ return { ...field, type: "enum" } as PossibleField
default:
return field
}
@@ -274,10 +267,13 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie
const fieldsToSync = fields
.filter(field => !ignoredFieldIds.has(field.id))
- .map(field => ({
- ...field,
- name: field.name.trim() || field.id,
- }))
+ .map(field => {
+ const originalFieldName = dataSource.fields.find(sourceField => sourceField.id === field.id)?.name
+ return {
+ ...field,
+ name: field.name.trim() || originalFieldName || field.id,
+ }
+ })
.filter(field => field.type !== "unsupported")
.filter(
field =>
@@ -313,18 +309,8 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie
return (
diff --git a/plugins/airtable/src/api.ts b/plugins/airtable/src/api.ts
index 248517a2f..8c0e2a6db 100644
--- a/plugins/airtable/src/api.ts
+++ b/plugins/airtable/src/api.ts
@@ -54,7 +54,6 @@ type CountValue = number
type DateValue = string
type DateTimeValue = string
type PhoneNumberValue = string
-type LookupValue = Array
type SingleSelectValue = string | Choice
type MultipleSelectsValue = string[] | Choice[]
type SingleCollaboratorValue = CollaboratorValue
@@ -104,7 +103,6 @@ export type AirtableFieldValues = {
createdTime: CreatedTimeValue
rollup: RollupValue
count: CountValue
- lookup: LookupValue
multipleLookupValues: MultipleLookupValuesValue
autoNumber: AutoNumberValue
barcode: BarcodeValue
@@ -197,7 +195,10 @@ interface FormulaOption {
interface RollupOption {
fieldIdInLinkedTable?: string
recordLinkFieldId?: string
- result?: AirtableFieldType | null
+ result?: {
+ type: AirtableFieldType
+ options?: AirtableFieldOptions[AirtableFieldType]
+ } | null
referencedFieldIds?: string[]
}
@@ -206,10 +207,13 @@ interface CountOption {
recordLinkFieldId?: string | null
}
-interface LookupOption {
+interface MultipleLookupValuesOption {
fieldIdInLinkedTable: string | null
recordLinkFieldId: string | null
- result: AirtableFieldType | null
+ result: {
+ type: AirtableFieldType
+ options?: AirtableFieldOptions[AirtableFieldType]
+ } | null
}
interface RatingOption {
@@ -265,8 +269,7 @@ type AirtableFieldOptions = {
createdTime: Record
rollup: RollupOption
count: CountOption
- lookup: LookupOption
- multipleLookupValues: LookupOption
+ multipleLookupValues: MultipleLookupValuesOption
autoNumber: Record
barcode: Record
rating: RatingOption
@@ -309,7 +312,6 @@ export type AirtableFieldSchema = AirtableBaseEntity & { description?: string }
| { type: "createdTime"; options: AirtableFieldOptions["createdTime"] }
| { type: "rollup"; options: AirtableFieldOptions["rollup"] }
| { type: "count"; options: AirtableFieldOptions["count"] }
- | { type: "lookup"; options: AirtableFieldOptions["lookup"] }
| { type: "multipleLookupValues"; options: AirtableFieldOptions["multipleLookupValues"] }
| { type: "autoNumber"; options: AirtableFieldOptions["autoNumber"] }
| { type: "barcode"; options: AirtableFieldOptions["barcode"] }
diff --git a/plugins/airtable/src/data.ts b/plugins/airtable/src/data.ts
index 3638e5afd..5d898f0e4 100644
--- a/plugins/airtable/src/data.ts
+++ b/plugins/airtable/src/data.ts
@@ -10,6 +10,7 @@ import type {
import { framer } from "framer-plugin"
import { type AirtableFieldSchema, fetchAllBases, fetchRecords, fetchTable, fetchTables } from "./api"
import type { PossibleField } from "./fields"
+import { inferFields } from "./fields"
import { richTextToHTML } from "./utils"
export const PLUGIN_KEYS = {
@@ -53,6 +54,12 @@ const EMAIL_REGEX = /\S[^\s@]*@\S+\.\S+/
const PHONE_REGEX = /^(\+?[0-9])[0-9]{7,14}$/
function getFieldDataEntryForFieldSchema(fieldSchema: PossibleField, value: unknown): FieldDataEntryInput | null {
+ if (fieldSchema.originalAirtableType === "multipleLookupValues") {
+ if (!Array.isArray(value)) return null
+ if (value.length === 0) return null
+ value = value[0]
+ }
+
switch (fieldSchema.type) {
case "boolean":
return {
@@ -122,6 +129,89 @@ function getFieldDataEntryForFieldSchema(fieldSchema: PossibleField, value: unkn
return null
case "string":
+ switch (fieldSchema.airtableType) {
+ case "barcode": {
+ if (!value || typeof value !== "object" || !("text" in value) || typeof value.text !== "string")
+ return null
+ return {
+ value: value.text,
+ type: "string",
+ }
+ }
+ case "aiText": {
+ if (!value || typeof value !== "object" || !("value" in value) || typeof value.value !== "string")
+ return null
+ return {
+ value: value.value,
+ type: "string",
+ }
+ }
+ case "duration": {
+ if (typeof value !== "number" || Number.isNaN(value)) return null
+
+ const hours = Math.floor(value / 3600)
+ const minutes = Math.floor((value % 3600) / 60)
+ const remainingSeconds = value % 60
+ const seconds = Math.floor(remainingSeconds).toString().padStart(2, "0")
+
+ let result = ""
+ result += hours.toString()
+ result += ":" + minutes.toString().padStart(2, "0")
+
+ // Handle seconds and milliseconds based on format
+ const durationOptions = fieldSchema.airtableOptions as { durationFormat?: string } | undefined
+ switch (durationOptions?.durationFormat) {
+ case "h:mm":
+ break
+ case "h:mm:ss":
+ result += ":" + seconds
+ break
+ case "h:mm:ss.S":
+ result += ":" + seconds
+ result += "." + (remainingSeconds % 1).toFixed(1).substring(2)
+ break
+ case "h:mm:ss.SS":
+ result += ":" + seconds
+ result += "." + (remainingSeconds % 1).toFixed(2).substring(2)
+ break
+ case "h:mm:ss.SSS":
+ result += ":" + seconds
+ result += "." + (remainingSeconds % 1).toFixed(3).substring(2)
+ break
+ }
+
+ return {
+ value: result,
+ type: "string",
+ }
+ }
+ case "singleCollaborator":
+ case "createdBy":
+ case "lastModifiedBy": {
+ if (!value || typeof value !== "object" || !("name" in value) || typeof value.name !== "string")
+ return null
+ return {
+ value: value.name,
+ type: "string",
+ }
+ }
+ case "multipleCollaborators": {
+ if (!Array.isArray(value) || value.length === 0) return null
+ const firstCollaborator = value[0]
+ if (
+ !firstCollaborator ||
+ typeof firstCollaborator !== "object" ||
+ !("name" in firstCollaborator) ||
+ typeof firstCollaborator.name !== "string"
+ )
+ return null
+ return {
+ value: firstCollaborator.name,
+ type: "string",
+ }
+ }
+ }
+
if (typeof value !== "string") return null
return {
value,
@@ -235,11 +325,17 @@ export async function getItems(dataSource: DataSource, slugFieldId: string) {
type: "boolean",
}
break
+ case "number":
+ fieldData[field.id] = {
+ value: 0,
+ type: "number",
+ }
+ break
case "image":
case "file":
case "link":
- case "date":
case "color":
+ case "date":
case "collectionReference":
case "multiCollectionReference":
fieldData[field.id] = {
@@ -351,18 +447,30 @@ export async function syncExistingCollection(
try {
await framer.hideUI()
- const existingFields = await collection.getFields()
const table = await fetchTable(previousBaseId, previousTableId)
if (!table) {
throw new Error(`Table “${previousTableName}” not found`)
}
+
+ // Use properly inferred fields instead of existing collection fields
+ const inferredFields = await inferFields(collection, table)
+
+ // Filter fields to match the format expected by syncCollection
+ const fieldsToSync = inferredFields
+ .filter(field => field.type !== "unsupported")
+ .filter(
+ field =>
+ (field.type !== "collectionReference" && field.type !== "multiCollectionReference") ||
+ field.collectionId !== ""
+ )
+
const dataSource: DataSource = {
baseId: previousBaseId,
tableId: previousTableId,
tableName: table.name,
- fields: existingFields,
+ fields: inferredFields,
}
- await syncCollection(collection, dataSource, existingFields, previousSlugFieldId)
+ await syncCollection(collection, dataSource, fieldsToSync, previousSlugFieldId)
return { didSync: true }
} catch (error) {
console.error(error)
diff --git a/plugins/airtable/src/fields.ts b/plugins/airtable/src/fields.ts
index aa93451fa..ba04bddd0 100644
--- a/plugins/airtable/src/fields.ts
+++ b/plugins/airtable/src/fields.ts
@@ -15,11 +15,17 @@ interface InferredField {
*/
readonly airtableType?: Exclude
readonly allowedTypes?: [AllowedType, ...AllowedType[]]
+ /**
+ * The original Airtable field schema options.
+ * Only set when fields are inferred.
+ */
+ readonly airtableOptions?: AirtableFieldSchema["options"]
}
interface InferredMultipleRecordLinksField {
type: "collectionReference" | "multiCollectionReference"
readonly airtableType: "multipleRecordLinks"
+ readonly airtableOptions?: AirtableFieldSchema["options"]
readonly single: boolean
readonly supportedCollections: { id: string; name: string }[]
readonly allowedTypes?: []
@@ -29,11 +35,14 @@ interface InferredEnumField {
type: "enum"
readonly airtableType: "singleSelect"
readonly airtableCases: { id: string; name: string }[]
+ readonly airtableOptions?: AirtableFieldSchema["options"]
readonly allowedTypes: ["enum"]
}
interface InferredUnsupportedField {
type: "unsupported"
+ readonly airtableType?: AirtableFieldSchema["type"]
+ readonly airtableOptions?: AirtableFieldSchema["options"]
readonly allowedTypes: [AirtableFieldSchema["type"], ...AirtableFieldSchema["type"][]]
}
@@ -46,7 +55,23 @@ export type PossibleField = (
type: "unsupported"
}
) &
- (InferredField | InferredMultipleRecordLinksField | InferredEnumField | InferredUnsupportedField)
+ (InferredField | InferredMultipleRecordLinksField | InferredEnumField | InferredUnsupportedField) & {
+ /**
+ * The original Airtable field type before any transformations.
+ * For lookup fields, this will be "multipleLookupValues".
+ */
+ readonly originalAirtableType?: string
+ }
+
+/**
+ * Creates the common metadata properties that are repeated across all inference functions
+ */
+function createFieldMetadata(fieldSchema: AirtableFieldSchema) {
+ return {
+ airtableOptions: fieldSchema.options,
+ originalAirtableType: fieldSchema.type,
+ }
+}
function inferBooleanField(fieldSchema: AirtableFieldSchema & { type: "checkbox" }): PossibleField {
return {
@@ -56,6 +81,7 @@ function inferBooleanField(fieldSchema: AirtableFieldSchema & { type: "checkbox"
airtableType: fieldSchema.type,
type: "boolean",
allowedTypes: ["boolean"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -75,12 +101,13 @@ function inferEnumField(fieldSchema: AirtableFieldSchema & { type: "singleSelect
name: choice.name,
})),
allowedTypes: ["enum"],
+ ...createFieldMetadata(fieldSchema),
}
}
function inferNumberField(
fieldSchema: AirtableFieldSchema & {
- type: "number" | "percent" | "currency" | "autoNumber" | "rating" | "duration"
+ type: "number" | "percent" | "currency" | "autoNumber" | "rating" | "count"
}
): PossibleField {
return {
@@ -90,6 +117,19 @@ function inferNumberField(
airtableType: fieldSchema.type,
type: "number",
allowedTypes: ["number"],
+ ...createFieldMetadata(fieldSchema),
+ }
+}
+
+function inferDurationField(fieldSchema: AirtableFieldSchema & { type: "duration" }): PossibleField {
+ return {
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ userEditable: false,
+ airtableType: fieldSchema.type,
+ type: "string",
+ allowedTypes: ["string", "number"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -101,6 +141,7 @@ function inferStringField(fieldSchema: AirtableFieldSchema & { type: "singleLine
airtableType: fieldSchema.type,
type: "string",
allowedTypes: ["string", "formattedText", "color"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -112,6 +153,7 @@ function inferEmailOrPhoneField(fieldSchema: AirtableFieldSchema & { type: "emai
airtableType: fieldSchema.type,
type: "string",
allowedTypes: ["string", "link"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -123,6 +165,7 @@ function inferTextField(fieldSchema: AirtableFieldSchema & { type: "multilineTex
airtableType: fieldSchema.type,
type: "formattedText",
allowedTypes: ["formattedText", "string"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -133,7 +176,8 @@ function inferUrlField(fieldSchema: AirtableFieldSchema & { type: "url" }): Poss
userEditable: false,
airtableType: fieldSchema.type,
type: "link",
- allowedTypes: ["link", "image", "file"],
+ allowedTypes: ["link", "image", "file", "string"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -145,6 +189,7 @@ function inferAttachmentsField(fieldSchema: AirtableFieldSchema & { type: "multi
airtableType: fieldSchema.type,
type: "image",
allowedTypes: ["image", "file", "link"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -160,9 +205,104 @@ function inferDateField(
airtableType: fieldSchema.type,
type: "date",
allowedTypes: ["date"],
+ ...createFieldMetadata(fieldSchema),
}
}
+function inferBarcodeField(fieldSchema: AirtableFieldSchema & { type: "barcode" }): PossibleField {
+ return {
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ userEditable: false,
+ airtableType: fieldSchema.type,
+ type: "string",
+ allowedTypes: ["string"],
+ ...createFieldMetadata(fieldSchema),
+ }
+}
+
+function inferAiTextField(fieldSchema: AirtableFieldSchema & { type: "aiText" }): PossibleField {
+ return {
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ userEditable: false,
+ airtableType: fieldSchema.type,
+ type: "string",
+ allowedTypes: ["string"],
+ ...createFieldMetadata(fieldSchema),
+ }
+}
+
+function inferCollaboratorField(
+ fieldSchema: AirtableFieldSchema & {
+ type: "singleCollaborator" | "createdBy" | "lastModifiedBy" | "multipleCollaborators"
+ }
+): PossibleField {
+ return {
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ userEditable: false,
+ airtableType: fieldSchema.type,
+ type: "string",
+ allowedTypes: ["string"],
+ ...createFieldMetadata(fieldSchema),
+ }
+}
+
+async function inferLookupField(
+ fieldSchema: AirtableFieldSchema & { type: "multipleLookupValues" },
+ collection: ManagedCollection,
+ tableIdBeingLinkedTo: string
+): Promise {
+ const { options } = fieldSchema
+
+ // If the lookup field doesn't have a result type, treat as unsupported
+ if (!options.result || typeof options.result !== "object" || !options.result.type) {
+ return createUnsupportedField(fieldSchema)
+ }
+
+ // Use the result object as the field schema for recursive inference
+ const resultSchema = {
+ type: options.result.type as AirtableFieldSchema["type"],
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ options: options.result.options as AirtableFieldSchema["options"],
+ } as AirtableFieldSchema
+
+ // Use the helper functions to infer the appropriate type based on the result
+ const inferredField = await inferFieldByType(resultSchema, collection, tableIdBeingLinkedTo, 1)
+
+ // Return the inferred field with the lookup field metadata
+ return { ...inferredField, originalAirtableType: "multipleLookupValues" } as PossibleField
+}
+
+async function inferRollupField(
+ fieldSchema: AirtableFieldSchema & { type: "rollup" },
+ collection: ManagedCollection,
+ tableIdBeingLinkedTo: string
+): Promise {
+ const { options } = fieldSchema
+
+ // If the rollup field doesn't have a result type, treat as unsupported
+ if (!options.result || typeof options.result !== "object" || !options.result.type) {
+ return createUnsupportedField(fieldSchema)
+ }
+
+ // Create a temporary schema with the result type for recursive inference
+ const resultSchema = {
+ id: fieldSchema.id,
+ name: fieldSchema.name,
+ type: options.result.type as AirtableFieldSchema["type"],
+ options: options.result.options as AirtableFieldSchema["options"],
+ } as AirtableFieldSchema
+
+ // Use the helper functions to infer the appropriate type based on the result
+ const inferredField = await inferFieldByType(resultSchema, collection, tableIdBeingLinkedTo, 1)
+
+ // Return the inferred field with the rollup field metadata
+ return { ...inferredField, originalAirtableType: "rollup" } as PossibleField
+}
+
async function inferRecordLinksField(
fieldSchema: AirtableFieldSchema & { type: "multipleRecordLinks" },
collection: ManagedCollection,
@@ -208,6 +348,7 @@ async function inferRecordLinksField(
collectionId: "",
supportedCollections: [],
single: fieldSchema.options.prefersSingleRecordLink,
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -220,6 +361,7 @@ async function inferRecordLinksField(
collectionId: foundCollection.id,
type,
single: fieldSchema.options.prefersSingleRecordLink,
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -252,7 +394,7 @@ async function inferFieldByType(
case "currency":
case "autoNumber":
case "rating":
- case "duration":
+ case "count":
return inferNumberField(fieldSchema)
case "singleLineText":
@@ -284,9 +426,26 @@ async function inferFieldByType(
case "formula":
return await inferFormulaField(fieldSchema, collection, tableIdBeingLinkedTo, depth)
- // Future support for Lookup/Rollup can be added here
- // case "lookup":
- // case "rollup":
+ case "barcode":
+ return inferBarcodeField(fieldSchema)
+
+ case "aiText":
+ return inferAiTextField(fieldSchema)
+
+ case "singleCollaborator":
+ case "createdBy":
+ case "lastModifiedBy":
+ case "multipleCollaborators":
+ return inferCollaboratorField(fieldSchema)
+
+ case "duration":
+ return inferDurationField(fieldSchema)
+
+ case "multipleLookupValues":
+ return await inferLookupField(fieldSchema, collection, tableIdBeingLinkedTo)
+
+ case "rollup":
+ return await inferRollupField(fieldSchema, collection, tableIdBeingLinkedTo)
default:
return createUnsupportedField(fieldSchema)
@@ -312,9 +471,11 @@ async function inferFormulaField(
id: fieldSchema.id,
name: fieldSchema.name,
userEditable: false,
+ airtableType: fieldSchema.type,
type: "file",
allowedFileTypes: ALLOWED_FILE_TYPES,
allowedTypes: ["file", "image", "link"],
+ ...createFieldMetadata(fieldSchema),
}
}
@@ -347,8 +508,10 @@ function createUnsupportedField(fieldSchema: AirtableFieldSchema): PossibleField
id: fieldSchema.id,
name: fieldSchema.name,
userEditable: false,
+ airtableType: fieldSchema.type,
type: "unsupported",
allowedTypes: [fieldSchema.type],
+ ...createFieldMetadata(fieldSchema),
}
}