From 4b6aa904408b097a691f187e96e1c41a9b0a51b6 Mon Sep 17 00:00:00 2001 From: Isaac Roberts <119639439+madebyisaacr@users.noreply.github.com> Date: Mon, 12 Jan 2026 13:31:04 -0500 Subject: [PATCH 1/5] Add time to Notion date fields --- plugins/notion/package.json | 2 +- plugins/notion/src/FieldMapping.tsx | 8 ++++--- plugins/notion/src/api.ts | 25 ++++++++++++--------- plugins/notion/src/data.ts | 35 ++++++++++++++++++++++++++--- yarn.lock | 2 +- 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/plugins/notion/package.json b/plugins/notion/package.json index 75123dd5a..b668041bd 100644 --- a/plugins/notion/package.json +++ b/plugins/notion/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@notionhq/client": "^3.1.3", - "framer-plugin": "^3.6.0", + "framer-plugin": "3.10.0-alpha.2", "react": "^18.3.1", "react-dom": "^18.3.1", "valibot": "^1.2.0" diff --git a/plugins/notion/src/FieldMapping.tsx b/plugins/notion/src/FieldMapping.tsx index 4b38baf37..ec808e7ba 100644 --- a/plugins/notion/src/FieldMapping.tsx +++ b/plugins/notion/src/FieldMapping.tsx @@ -10,6 +10,7 @@ import { useEffect, useMemo, useState } from "react" import { type FieldId, type FieldInfo, + type VirtualFieldType, getDatabaseFieldsInfo, getPossibleSlugFieldIds, isMissingCollection, @@ -25,9 +26,10 @@ import { } from "./data" import { assert, syncMethods } from "./utils" -const labelByFieldTypeOption: Record = { +const labelByFieldTypeOption: Record = { boolean: "Toggle", date: "Date", + dateTime: "Date & Time", number: "Number", formattedText: "Formatted Text", color: "Color", @@ -49,7 +51,7 @@ interface FieldMappingRowProps { missingCollection: boolean onToggleIgnored: (fieldId: string) => void onNameChange: (fieldId: string, name: string) => void - onFieldTypeChange: (fieldId: string, type: ManagedCollectionField["type"]) => void + onFieldTypeChange: (fieldId: string, type: VirtualFieldType) => void } function FieldMappingRow({ @@ -211,7 +213,7 @@ export function FieldMapping({ }) } - const changeFieldType = (fieldId: string, type: ManagedCollectionField["type"]) => { + const changeFieldType = (fieldId: string, type: VirtualFieldType) => { setFieldsInfo(prevFieldsInfo => { const updatedFieldInfo = prevFieldsInfo.map(fieldInfo => { if (fieldInfo.id !== fieldId) return fieldInfo diff --git a/plugins/notion/src/api.ts b/plugins/notion/src/api.ts index f3c8d3062..4cdcf9446 100644 --- a/plugins/notion/src/api.ts +++ b/plugins/notion/src/api.ts @@ -27,12 +27,14 @@ const LAST_CONTENT_IMPORTING_UPDATE_DATE = new Date("2025-07-01T12:00:00.000Z") export type FieldId = string +export type VirtualFieldType = ManagedCollectionField["type"] | "dateTime" + export interface FieldInfo { id: FieldId name: string originalName: string - type: ManagedCollectionField["type"] | null - allowedTypes: ManagedCollectionField["type"][] + type: VirtualFieldType | null + allowedTypes: VirtualFieldType[] notionProperty: NotionProperty | null } @@ -66,12 +68,12 @@ const slugFieldTypes: NotionProperty["type"][] = ["title", "rich_text", "unique_ export const supportedCMSTypeByNotionPropertyType = { checkbox: ["boolean"], - date: ["date"], + date: ["dateTime", "date"], number: ["number"], title: ["string"], rich_text: ["formattedText", "string", "color"], - created_time: ["date"], - last_edited_time: ["date"], + created_time: ["dateTime", "date"], + last_edited_time: ["dateTime", "date"], select: ["enum"], status: ["enum"], url: ["link"], @@ -80,8 +82,8 @@ export const supportedCMSTypeByNotionPropertyType = { files: ["file", "image", "array"], relation: ["multiCollectionReference", "collectionReference"], unique_id: ["string", "number"], - formula: ["string", "number", "boolean", "date", "link", "color"], -} satisfies Partial> + formula: ["string", "number", "boolean", "date", "dateTime", "link", "color"], +} satisfies Partial> // Naive implementation to be authenticated, a token could be expired. // For simplicity we just close the plugin and clear storage in that case. @@ -216,15 +218,18 @@ export async function getNotionDatabases() { export function assertFieldTypeMatchesPropertyType( propertyType: NotionProperty["type"], - fieldType: ManagedCollectionField["type"] -): asserts fieldType is ManagedCollectionField["type"] { + fieldType: VirtualFieldType | ManagedCollectionField["type"] +): void { if (!isSupportedPropertyType(propertyType)) { throw new Error(`Property type '${propertyType}' is not supported.`) } const allowedFieldTypes = supportedCMSTypeByNotionPropertyType[propertyType] - if (!allowedFieldTypes.includes(fieldType as never)) { + // For dateTime, treat it as "date" for validation purposes + const typeToCheck = fieldType === "dateTime" ? "date" : fieldType + + if (!allowedFieldTypes.includes(typeToCheck as never)) { throw new Error(`Field type '${fieldType}' is not valid for property type '${propertyType}'.`) } } diff --git a/plugins/notion/src/data.ts b/plugins/notion/src/data.ts index fbb782929..493c0c9cb 100644 --- a/plugins/notion/src/data.ts +++ b/plugins/notion/src/data.ts @@ -75,8 +75,16 @@ export function mergeFieldsInfoWithExistingFields( ): FieldInfo[] { return sourceFieldsInfo.map(sourceFieldInfo => { const existingField = existingFields.find(existingField => existingField.id === sourceFieldInfo.id) - if (existingField && sourceFieldInfo.allowedTypes.includes(existingField.type)) { - return { ...sourceFieldInfo, name: existingField.name, type: existingField.type } + if (existingField) { + // Handle date fields with displayTime: convert to dateTime virtual type + let fieldType: FieldInfo["type"] = existingField.type + if (existingField.type === "date" && "displayTime" in existingField && existingField.displayTime === true) { + fieldType = "dateTime" + } + + if (sourceFieldInfo.allowedTypes.includes(fieldType)) { + return { ...sourceFieldInfo, name: existingField.name, type: fieldType } + } } return sourceFieldInfo }) @@ -433,7 +441,6 @@ export function fieldsInfoToCollectionFields( switch (fieldType) { case "boolean": - case "date": case "number": case "string": case "formattedText": @@ -449,6 +456,28 @@ export function fieldsInfoToCollectionFields( }) break } + case "date": { + assertFieldTypeMatchesPropertyType(property.type, fieldType) + fields.push({ + type: "date", + id: fieldInfo.id, + name: fieldName, + userEditable: false, + displayTime: false, + }) + break + } + case "dateTime": { + assertFieldTypeMatchesPropertyType(property.type, "date") + fields.push({ + type: "date", + id: fieldInfo.id, + name: fieldName, + userEditable: false, + displayTime: true, + }) + break + } case "enum": { assertFieldTypeMatchesPropertyType(property.type, fieldType) diff --git a/yarn.lock b/yarn.lock index f261d270e..7079aee05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5661,7 +5661,7 @@ __metadata: "@notionhq/client": "npm:^3.1.3" "@types/react": "npm:^18.3.24" "@types/react-dom": "npm:^18.3.7" - framer-plugin: "npm:^3.6.0" + framer-plugin: "npm:3.10.0-alpha.2" framer-plugin-tools: "npm:^1.0.0" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" From aa8d5c62c3292ad0a3152fcd4522d2b38fbb3afb Mon Sep 17 00:00:00 2001 From: Isaac Roberts <119639439+madebyisaacr@users.noreply.github.com> Date: Mon, 12 Jan 2026 13:48:30 -0500 Subject: [PATCH 2/5] Biome fix --- plugins/notion/src/FieldMapping.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/notion/src/FieldMapping.tsx b/plugins/notion/src/FieldMapping.tsx index ec808e7ba..d9b52f01c 100644 --- a/plugins/notion/src/FieldMapping.tsx +++ b/plugins/notion/src/FieldMapping.tsx @@ -10,10 +10,10 @@ import { useEffect, useMemo, useState } from "react" import { type FieldId, type FieldInfo, - type VirtualFieldType, getDatabaseFieldsInfo, getPossibleSlugFieldIds, isMissingCollection, + type VirtualFieldType, } from "./api" import { type DatabaseIdMap, From e27ab8e9692b0f40662d399bb8502c1b36dbf4a3 Mon Sep 17 00:00:00 2001 From: Isaac Roberts <119639439+madebyisaacr@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:03:27 -0500 Subject: [PATCH 3/5] Improve types --- plugins/notion/src/FieldMapping.tsx | 2 +- plugins/notion/src/api.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/notion/src/FieldMapping.tsx b/plugins/notion/src/FieldMapping.tsx index d9b52f01c..9ee2315d9 100644 --- a/plugins/notion/src/FieldMapping.tsx +++ b/plugins/notion/src/FieldMapping.tsx @@ -26,7 +26,7 @@ import { } from "./data" import { assert, syncMethods } from "./utils" -const labelByFieldTypeOption: Record = { +const labelByFieldTypeOption: Record = { boolean: "Toggle", date: "Date", dateTime: "Date & Time", diff --git a/plugins/notion/src/api.ts b/plugins/notion/src/api.ts index 4cdcf9446..377c3414f 100644 --- a/plugins/notion/src/api.ts +++ b/plugins/notion/src/api.ts @@ -83,7 +83,7 @@ export const supportedCMSTypeByNotionPropertyType = { relation: ["multiCollectionReference", "collectionReference"], unique_id: ["string", "number"], formula: ["string", "number", "boolean", "date", "dateTime", "link", "color"], -} satisfies Partial> +} satisfies Partial> // Naive implementation to be authenticated, a token could be expired. // For simplicity we just close the plugin and clear storage in that case. @@ -218,7 +218,7 @@ export async function getNotionDatabases() { export function assertFieldTypeMatchesPropertyType( propertyType: NotionProperty["type"], - fieldType: VirtualFieldType | ManagedCollectionField["type"] + fieldType: VirtualFieldType ): void { if (!isSupportedPropertyType(propertyType)) { throw new Error(`Property type '${propertyType}' is not supported.`) From 59066aaf914091fcaab721c145b3c9799f86958f Mon Sep 17 00:00:00 2001 From: Isaac Roberts <119639439+madebyisaacr@users.noreply.github.com> Date: Mon, 19 Jan 2026 10:30:19 -0500 Subject: [PATCH 4/5] Update framer-plugin --- plugins/notion/package.json | 2 +- yarn.lock | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/notion/package.json b/plugins/notion/package.json index b668041bd..b5516ce39 100644 --- a/plugins/notion/package.json +++ b/plugins/notion/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@notionhq/client": "^3.1.3", - "framer-plugin": "3.10.0-alpha.2", + "framer-plugin": "^3.10.2", "react": "^18.3.1", "react-dom": "^18.3.1", "valibot": "^1.2.0" diff --git a/yarn.lock b/yarn.lock index 7079aee05..7f342b309 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4603,6 +4603,16 @@ __metadata: languageName: node linkType: hard +"framer-plugin@npm:^3.10.2": + version: 3.10.2 + resolution: "framer-plugin@npm:3.10.2" + peerDependencies: + react: ^18.2.0 + react-dom: ^18.2.0 + checksum: 10/34a230043798343d09603fbf45a5f59a974877ee4b8ea9cdd1bee54d9407220d232f17951fe2a5849883bf127eb2c3c1f385d8972914fa8db096984fb8c64486 + languageName: node + linkType: hard + "framer-plugin@npm:^3.6.0": version: 3.6.0 resolution: "framer-plugin@npm:3.6.0" @@ -5661,7 +5671,7 @@ __metadata: "@notionhq/client": "npm:^3.1.3" "@types/react": "npm:^18.3.24" "@types/react-dom": "npm:^18.3.7" - framer-plugin: "npm:3.10.0-alpha.2" + framer-plugin: "npm:^3.10.2" framer-plugin-tools: "npm:^1.0.0" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" From d1d0483bc4de49c4e1f5d30bf2370300584c555d Mon Sep 17 00:00:00 2001 From: Isaac Roberts <119639439+madebyisaacr@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:07:56 -0500 Subject: [PATCH 5/5] Fix lockfile error --- plugins/csv-import/package.json | 2 +- yarn.lock | 12 +----------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/plugins/csv-import/package.json b/plugins/csv-import/package.json index f5aec3b95..5952d0582 100644 --- a/plugins/csv-import/package.json +++ b/plugins/csv-import/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "csv-parse": "^6.1.0", - "framer-plugin": "3.10.2", + "framer-plugin": "^3.10.2", "react": "^18.3.1", "react-dom": "^18.3.1", "valibot": "^1.2.0" diff --git a/yarn.lock b/yarn.lock index 7f342b309..b0f6d922e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3713,7 +3713,7 @@ __metadata: "@types/react": "npm:^18.3.24" "@types/react-dom": "npm:^18.3.7" csv-parse: "npm:^6.1.0" - framer-plugin: "npm:3.10.2" + framer-plugin: "npm:^3.10.2" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" valibot: "npm:^1.2.0" @@ -4573,16 +4573,6 @@ __metadata: languageName: node linkType: hard -"framer-plugin@npm:3.10.2": - version: 3.10.2 - resolution: "framer-plugin@npm:3.10.2" - peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 - checksum: 10/34a230043798343d09603fbf45a5f59a974877ee4b8ea9cdd1bee54d9407220d232f17951fe2a5849883bf127eb2c3c1f385d8972914fa8db096984fb8c64486 - languageName: node - linkType: hard - "framer-plugin@npm:3.7.0-alpha.0": version: 3.7.0-alpha.0 resolution: "framer-plugin@npm:3.7.0-alpha.0"