import type { ReactNode } from "react"; import { useEffect, useState } from "react"; import type { InferredTypeMap } from "ra-core"; import { EditBase, InferredElement, useResourceContext, useEditContext, getElementsFromRecords, } from "ra-core"; import { capitalize, singularize } from "inflection"; import { EditView } from "@/components/admin/edit"; import { SimpleForm } from "@/components/admin/simple-form"; import { TextInput } from "@/components/admin/text-input"; import { BooleanInput } from "@/components/admin/boolean-input"; import { ReferenceInput } from "@/components/admin/reference-input"; import { AutocompleteInput } from "@/components/admin/autocomplete-input"; import { ReferenceArrayInput } from "@/components/admin/reference-array-input"; /** * An edit page that automatically generates a form from your data. * * Inspects the record to infer field types and automatically creates appropriate inputs. * Useful for rapid prototyping. Logs generated code to console. * * @see {@link https://marmelab.com/shadcn-admin-kit/docs/edit/#scaffolding-an-edit-page EditGuesser documentation} * * @example * import { Admin, EditGuesser } from '@/components/admin'; * import { Resource } from 'ra-core'; * import dataProvider from './dataProvider'; * * const App = () => ( * * ... * * * ); */ export const EditGuesser = (props: { enableLog?: boolean }) => { return ( ); }; const EditViewGuesser = (props: { enableLog?: boolean }) => { const resource = useResourceContext(); if (!resource) { throw new Error(`Cannot use outside of a ResourceContext`); } const { record } = useEditContext(); const [child, setChild] = useState(null); const { enableLog = process.env.NODE_ENV === "development", ...rest } = props; useEffect(() => { setChild(null); }, [resource]); useEffect(() => { if (record && !child) { const inferredElements = getElementsFromRecords([record], editFieldTypes); const inferredChild = new InferredElement( editFieldTypes.form, null, inferredElements, ); setChild(inferredChild.getElement()); if (!enableLog) return; const representation = inferredChild.getRepresentation(); const components = ["Edit"] .concat( Array.from( new Set( Array.from(representation.matchAll(/<([^/\s>]+)/g)) .map((match) => match[1]) .filter((component) => component !== "span"), ), ), ) .sort(); // eslint-disable-next-line no-console console.log( `Guessed Edit: ${components .map( (component) => `import { ${component} } from "@/components/admin/${kebabCase( component, )}";`, ) .join("\n")} export const ${capitalize(singularize(resource))}Edit = () => ( ${representation} );`, ); } }, [record, child, resource, enableLog]); return {child}; }; const editFieldTypes: InferredTypeMap = { form: { component: (props: any) => , representation: ( _props: any, children: { getRepresentation: () => string }[], ) => ` ${children .map((child) => ` ${child.getRepresentation()}`) .join("\n")} `, }, reference: { component: (props: any) => ( ), representation: (props: any) => ` `, }, referenceArray: { component: (props: any) => , representation: (props: any) => ``, }, boolean: { component: (props: any) => , representation: (props: any) => ``, }, string: { component: (props: any) => , representation: (props: any) => ``, }, }; const kebabCase = (name: string) => { return name .replace(/([a-z])([A-Z])/g, "$1-$2") .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2") .toLowerCase(); };