"use client"; import { useMemo, useState } from "react"; import { Plus, Trash2, X, ChevronLeft } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/primitives"; import { cn } from "@/lib/utils"; import type { Property, PropertyType, PropertyConfig, SelectOption, OptionColor } from "@/lib/databases/types"; import { PROPERTY_TYPES, AGGREGATES, OPTION_COLORS } from "@/lib/databases/types"; import { evaluate, FORMULA_HELP } from "@/lib/databases/formula"; import { formulaValue, newId, pickColor, displayValue } from "@/lib/databases/values"; import { useDb, usePropertyMutations, useAllDatabases, useRemoteDatabase } from "./hooks"; import { TYPE_META, TypeIcon, Sel, Field, inputCls } from "./meta"; import { DOT_CLASS } from "./colors"; import { OptionChip } from "./cells/SelectCell"; const CREATABLE = PROPERTY_TYPES.filter((t) => t !== "title"); const OPT_TYPES: PropertyType[] = ["select", "multi_select", "status"]; /** Create (prop undefined) or edit a property. Renders inside a popover/dialog. */ export function PropertyEditor({ prop, onClose, onBack }: { prop?: Property; onClose: () => void; onBack?: () => void }) { const ctx = useDb(); const m = usePropertyMutations(ctx.db, ctx.db.pageId); const [name, setName] = useState(prop?.name ?? ""); const [type, setType] = useState(prop?.type ?? "text"); const [config, setConfig] = useState(prop?.config ?? {}); const [pickType, setPickType] = useState(!prop); const [confirm, setConfirm] = useState(false); const set = (c: Partial) => setConfig((x) => ({ ...x, ...c })); const changeType = (t: PropertyType) => { setType(t); setPickType(false); if (!prop || prop.type !== t) setConfig(OPT_TYPES.includes(type) && OPT_TYPES.includes(t) && config.options?.length ? { options: config.options } : {}); if (!name) setName(TYPE_META[t].label); }; const save = async () => { const n = name.trim() || TYPE_META[type].label; if (type === "relation" && !config.targetDatabaseId) return; if (prop) await m.update.mutateAsync({ id: prop.id, ...(n !== prop.name ? { name: n } : {}), ...(type !== prop.type ? { type } : {}), config }); else await m.create.mutateAsync({ name: n, type, config }); onClose(); }; if (pickType) return (
{prop && }{prop ? "Change type" : "Property type"}
{CREATABLE.map((t) => )}
{prop && prop.type !== type &&
Changing the type converts existing values when possible.
}
); return (
{onBack && }{prop ? "Edit property" : "New property"}
setName(e.target.value)} placeholder="Property name" autoFocus className={inputCls} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); save(); } if (e.key === "Escape") onClose(); }} />
{prop && prop.type !== "title" && (confirm ? : )}
); } function ConfigEditor({ type, config, set, prop }: { type: PropertyType; config: PropertyConfig; set: (c: Partial) => void; prop?: Property }) { const ctx = useDb(); switch (type) { case "select": case "multi_select": case "status": return set({ options })} />; case "number": return set({ format: e.target.value as any })} className="w-full">; case "date": return ; case "relation": return ; case "rollup": return ; case "formula": return ; case "ai": return