diff --git a/plugins/airtable/src/App.css b/plugins/airtable/src/App.css index 1118b6430..0ac6de992 100644 --- a/plugins/airtable/src/App.css +++ b/plugins/airtable/src/App.css @@ -225,3 +225,19 @@ select:not(:disabled) { flex: 1; width: 100%; } + +.note { + display: flex; + flex-direction: row; + align-items: start; + justify-content: left; + gap: 14px; + width: 100%; + padding-left: 4px; + color: var(--framer-color-text-tertiary); +} + +.note svg { + margin-top: 3px; + flex-shrink: 0; +} diff --git a/plugins/airtable/src/App.tsx b/plugins/airtable/src/App.tsx index 7cf79d8b4..433cec47d 100644 --- a/plugins/airtable/src/App.tsx +++ b/plugins/airtable/src/App.tsx @@ -17,9 +17,16 @@ interface AppProps { previousBaseId: string | null previousTableId: string | null previousSlugFieldId: string | null + previousLastSynced: string | null } -export function App({ collection, previousBaseId, previousTableId, previousSlugFieldId }: AppProps) { +export function App({ + collection, + previousBaseId, + previousTableId, + previousSlugFieldId, + previousLastSynced, +}: AppProps) { const [dataSource, setDataSource] = useState(null) const [isLoadingDataSource, setIsLoadingDataSource] = useState(Boolean(previousBaseId && previousTableId)) const [noTableAccess, setNoTableAccess] = useState(false) @@ -97,5 +104,12 @@ export function App({ collection, previousBaseId, previousTableId, previousSlugF return } - return + return ( + + ) } diff --git a/plugins/airtable/src/FieldMapping.tsx b/plugins/airtable/src/FieldMapping.tsx index c102102c9..6229e09eb 100644 --- a/plugins/airtable/src/FieldMapping.tsx +++ b/plugins/airtable/src/FieldMapping.tsx @@ -2,7 +2,7 @@ import type { Field, ManagedCollection, ManagedCollectionField, ManagedCollectio import { FramerPluginClosedError, framer, useIsAllowedTo } from "framer-plugin" import { memo, useEffect, useMemo, useState } from "react" import type { DataSource } from "./data" -import { mergeFieldsWithExistingFields, syncCollection, syncMethods } from "./data" +import { isFullLastModifiedTimeField, mergeFieldsWithExistingFields, syncCollection, syncMethods } from "./data" import type { PossibleField } from "./fields" import { isCollectionReference } from "./utils" @@ -147,9 +147,10 @@ interface FieldMappingProps { collection: ManagedCollection dataSource: DataSource initialSlugFieldId: string | null + previousLastSynced: string | null } -export function FieldMapping({ collection, dataSource, initialSlugFieldId }: FieldMappingProps) { +export function FieldMapping({ collection, dataSource, initialSlugFieldId, previousLastSynced }: FieldMappingProps) { const [status, setStatus] = useState<"mapping-fields" | "loading-fields" | "syncing-collection">( initialSlugFieldId ? "loading-fields" : "mapping-fields" ) @@ -165,6 +166,8 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie const [fields, setFields] = useState(initialManagedCollectionFields) const [ignoredFieldIds, setIgnoredFieldIds] = useState(initialFieldIds) + const hasLastModifiedTimeField = dataSource.fields.some(isFullLastModifiedTimeField) + // Create a map of field IDs to names for efficient lookup const originalFieldNameMap = useMemo( () => new Map(dataSource.fields.map(field => [field.id, field.name])), @@ -310,8 +313,17 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie field.collectionId !== "" ) + const syncStartedAtDate = new Date().toISOString() + await collection.setFields(processFields(fieldsToSync)) - await syncCollection(collection, dataSource, fieldsToSync, selectedSlugField.id) + await syncCollection( + collection, + dataSource, + fieldsToSync, + selectedSlugField.id, + previousLastSynced, + syncStartedAtDate + ) framer.closePlugin("Synchronization successful", { variant: "success", }) @@ -347,6 +359,21 @@ export function FieldMapping({ collection, dataSource, initialSlugFieldId }: Fie

+ {!hasLastModifiedTimeField && ( + <> +
+ + + +

Add a “Last Modified Time” column in Airtable to sync faster.

+
+
+ + )} +