From 32fe1ca2214f221d07560244c6e7510adc94a886 Mon Sep 17 00:00:00 2001 From: foyarash <11079152+foyarash@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:29:44 +0100 Subject: [PATCH 1/8] feat: add support for json fields --- .changeset/tall-guests-jam.md | 5 +++ apps/example/components/JsonEditor.tsx | 37 +++++++++++++++++++ apps/example/options.tsx | 16 ++++++++ apps/example/package.json | 1 + .../prisma/json-schema/json-schema.json | 10 +++++ .../migration.sql | 2 + apps/example/prisma/schema.prisma | 1 + packages/next-admin/src/utils/props.ts | 26 +++++-------- packages/next-admin/src/utils/server.ts | 14 +++++++ yarn.lock | 19 ++++++++++ 10 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 .changeset/tall-guests-jam.md create mode 100644 apps/example/components/JsonEditor.tsx create mode 100644 apps/example/prisma/migrations/20231208102028_user_metadata/migration.sql diff --git a/.changeset/tall-guests-jam.md b/.changeset/tall-guests-jam.md new file mode 100644 index 00000000..2eae2d79 --- /dev/null +++ b/.changeset/tall-guests-jam.md @@ -0,0 +1,5 @@ +--- +"@premieroctet/next-admin": minor +--- + +🛠 add support for JSON fields diff --git a/apps/example/components/JsonEditor.tsx b/apps/example/components/JsonEditor.tsx new file mode 100644 index 00000000..4b89abd4 --- /dev/null +++ b/apps/example/components/JsonEditor.tsx @@ -0,0 +1,37 @@ +"use client" +import Editor from '@monaco-editor/react'; +import { CustomInputProps } from '@premieroctet/next-admin'; +import { useMemo } from 'react'; + +type Props = CustomInputProps + +const JsonEditor = ({ value, onChange, name }: Props) => { + const defaultValue = useMemo(() => { + try { + return JSON.stringify(JSON.parse(value!), null, 2) + } catch { + return "" + } + }, []) + + return ( + <> + + { + // @ts-expect-error + onChange?.({ target: { value: val ?? "" }}) + }} + options={{ + minimap: { enabled: false } + }} + className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 px-2 disabled:opacity-50 disabled:bg-gray-200 disabled:cursor-not-allowed [&>div]:border-none" + /> + + ) +} + +export default JsonEditor \ No newline at end of file diff --git a/apps/example/options.tsx b/apps/example/options.tsx index 10b5ffe8..54acf995 100644 --- a/apps/example/options.tsx +++ b/apps/example/options.tsx @@ -1,6 +1,7 @@ import { NextAdminOptions } from "@premieroctet/next-admin"; import React from "react"; import DatePicker from "./components/DatePicker"; +import JsonEditor from "./components/JsonEditor"; export const options: NextAdminOptions = { basePath: "/admin", @@ -35,6 +36,7 @@ export const options: NextAdminOptions = { "role", "birthDate", "avatar", + "metadata" ], fields: { email: { @@ -56,6 +58,20 @@ export const options: NextAdminOptions = { }, }, }, + metadata: { + input: , + validate: (value) => { + try { + if (!value) { + return true + } + JSON.parse(value as string) + return true + } catch { + return "Invalid JSON" + } + } + } }, }, }, diff --git a/apps/example/package.json b/apps/example/package.json index 51445d81..778b34ba 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "@heroicons/react": "^2.0.18", + "@monaco-editor/react": "^4.6.0", "@picocss/pico": "^1.5.7", "@premieroctet/next-admin": "*", "@prisma/client": "^5.2.0", diff --git a/apps/example/prisma/json-schema/json-schema.json b/apps/example/prisma/json-schema/json-schema.json index 1750a451..407ae0f4 100644 --- a/apps/example/prisma/json-schema/json-schema.json +++ b/apps/example/prisma/json-schema/json-schema.json @@ -60,6 +60,16 @@ "string", "null" ] + }, + "metadata": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ] } }, "required": [ diff --git a/apps/example/prisma/migrations/20231208102028_user_metadata/migration.sql b/apps/example/prisma/migrations/20231208102028_user_metadata/migration.sql new file mode 100644 index 00000000..b3886efa --- /dev/null +++ b/apps/example/prisma/migrations/20231208102028_user_metadata/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "metadata" JSONB; diff --git a/apps/example/prisma/schema.prisma b/apps/example/prisma/schema.prisma index 0e585817..9f20b798 100644 --- a/apps/example/prisma/schema.prisma +++ b/apps/example/prisma/schema.prisma @@ -33,6 +33,7 @@ model User { updatedAt DateTime @default(now()) @updatedAt role Role @default(USER) avatar String? + metadata Json? } model Post { diff --git a/packages/next-admin/src/utils/props.ts b/packages/next-admin/src/utils/props.ts index 711ee5ba..6cf9c894 100644 --- a/packages/next-admin/src/utils/props.ts +++ b/packages/next-admin/src/utils/props.ts @@ -70,13 +70,10 @@ export async function getPropsFromParams({ message, } = getMainLayoutProps({ options, params, searchParams, isAppDir }); - const resourcesIdProperty = resources!.reduce( - (acc, resource) => { - acc[resource] = getModelIdProperty(resource); - return acc; - }, - {} as Record - ); + const resourcesIdProperty = resources!.reduce((acc, resource) => { + acc[resource] = getModelIdProperty(resource); + return acc; + }, {} as Record); if (isAppDir && !action) { throw new Error("action is required when using App router"); @@ -222,15 +219,12 @@ export const getMainLayoutProps = ({ : null; } catch {} - const resourcesTitles = resources.reduce( - (acc, resource) => { - acc[resource as Prisma.ModelName] = - options.model?.[resource as keyof typeof options.model]?.title ?? - resource; - return acc; - }, - {} as { [key in Prisma.ModelName]: string } - ); + const resourcesTitles = resources.reduce((acc, resource) => { + acc[resource as Prisma.ModelName] = + options.model?.[resource as keyof typeof options.model]?.title ?? + resource; + return acc; + }, {} as { [key in Prisma.ModelName]: string }); return { resources, diff --git a/packages/next-admin/src/utils/server.ts b/packages/next-admin/src/utils/server.ts index 084219a4..29abd0ea 100644 --- a/packages/next-admin/src/utils/server.ts +++ b/packages/next-admin/src/utils/server.ts @@ -202,6 +202,8 @@ export const transformData = ( const fieldTypes = field?.type; if (fieldTypes === "DateTime") { acc[key] = data[key] ? data[key].toISOString() : null; + } else if (fieldTypes === "Json") { + acc[key] = data[key] ? JSON.stringify(data[key]) : null; } else { acc[key] = data[key] ? data[key] : null; } @@ -379,6 +381,14 @@ export const formattedFormData = async ( } else if (dmmfPropertyType === "DateTime") { formattedData[dmmfPropertyName] = formData[dmmfPropertyName] || null; + } else if (dmmfPropertyType === "Json") { + try { + formattedData[dmmfPropertyName] = formData[dmmfPropertyName] + ? JSON.parse(formData[dmmfPropertyName]!) + : null; + } catch { + // no-op + } } else if ( dmmfPropertyType === "String" && ["data-url", "file"].includes( @@ -462,6 +472,10 @@ export const changeFormatInSchema = ( dmmfPropertyName as Field ]; + if (fieldValue && dmmfProperty.type === "Json") { + fieldValue.type = "string"; + } + if (fieldValue && editOptions?.fields?.[dmmfPropertyName]?.input) { fieldValue.format = "string"; } else if (editOptions?.fields?.[dmmfPropertyName]?.format) { diff --git a/yarn.lock b/yarn.lock index 795e7ed1..c1d347f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1113,6 +1113,20 @@ "@types/mdx" "^2.0.0" "@types/react" ">=16" +"@monaco-editor/loader@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.4.0.tgz#f08227057331ec890fa1e903912a5b711a2ad558" + integrity sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg== + dependencies: + state-local "^1.0.6" + +"@monaco-editor/react@^4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.6.0.tgz#bcc68671e358a21c3814566b865a54b191e24119" + integrity sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw== + dependencies: + "@monaco-editor/loader" "^1.4.0" + "@napi-rs/simple-git-android-arm-eabi@0.1.9": version "0.1.9" resolved "https://registry.yarnpkg.com/@napi-rs/simple-git-android-arm-eabi/-/simple-git-android-arm-eabi-0.1.9.tgz#0326fbc4ffafb678bda3474018e2a24a8d2a21b6" @@ -8878,6 +8892,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +state-local@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5" + integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w== + statuses@2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" From cff5e552679b2a8e966db9175840bcf324692db2 Mon Sep 17 00:00:00 2001 From: foyarash <11079152+foyarash@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:52:39 +0100 Subject: [PATCH 2/8] Fix user mocks --- packages/next-admin/src/tests/serverUtils.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/next-admin/src/tests/serverUtils.test.ts b/packages/next-admin/src/tests/serverUtils.test.ts index 028661c2..ec9a878d 100644 --- a/packages/next-admin/src/tests/serverUtils.test.ts +++ b/packages/next-admin/src/tests/serverUtils.test.ts @@ -17,6 +17,7 @@ describe("fillRelationInSchema", () => { birthDate: new Date(), role: "ADMIN", avatar: null, + metadata: null }, { id: 2, @@ -27,6 +28,7 @@ describe("fillRelationInSchema", () => { birthDate: new Date(), role: "ADMIN", avatar: null, + metadata: null }, ]); const result = await fillRelationInSchema(schema, prismaMock, "Post", {}); From bb48e50a012a3bb7e0baf563044ca6a3b862d687 Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Thu, 4 Jan 2024 11:23:56 +0100 Subject: [PATCH 3/8] add json editor in nextadmin core --- apps/example/options.tsx | 4 +--- packages/next-admin/src/components/Form.tsx | 23 +++++++++++++------ .../src/components/inputs/JsonField.tsx | 6 ++--- packages/next-admin/src/types.ts | 1 + 4 files changed, 21 insertions(+), 13 deletions(-) rename apps/example/components/JsonEditor.tsx => packages/next-admin/src/components/inputs/JsonField.tsx (90%) diff --git a/apps/example/options.tsx b/apps/example/options.tsx index d9eeb58a..4b83c3eb 100644 --- a/apps/example/options.tsx +++ b/apps/example/options.tsx @@ -1,7 +1,5 @@ import { NextAdminOptions } from "@premieroctet/next-admin"; -import React from "react"; import DatePicker from "./components/DatePicker"; -import JsonEditor from "./components/JsonEditor"; export const options: NextAdminOptions = { basePath: "/admin", @@ -59,7 +57,7 @@ export const options: NextAdminOptions = { }, }, metadata: { - input: , + format: "json", validate: (value) => { try { if (!value) { diff --git a/packages/next-admin/src/components/Form.tsx b/packages/next-admin/src/components/Form.tsx index fcbcc6f0..3791463d 100644 --- a/packages/next-admin/src/components/Form.tsx +++ b/packages/next-admin/src/components/Form.tsx @@ -11,19 +11,20 @@ import { import validator from "@rjsf/validator-ajv8"; import clsx from "clsx"; import { ChangeEvent, cloneElement, useMemo, useState } from "react"; +import { useConfig } from "../context/ConfigContext"; import { PropertyValidationError } from "../exceptions/ValidationError"; +import { useRouterInternal } from "../hooks/useRouterInternal"; import { Field, ModelAction, ModelName, SubmitFormResult } from "../types"; -import { Schemas, getSchemas } from "../utils/jsonSchema"; +import { getSchemas } from "../utils/jsonSchema"; +import ActionsDropdown from "./ActionsDropdown"; import ArrayField from "./inputs/ArrayField"; import CheckboxWidget from "./inputs/CheckboxWidget"; -import SelectWidget from "./inputs/SelectWidget"; -import Button from "./radix/Button"; import DateTimeWidget from "./inputs/DateTimeWidget"; import DateWidget from "./inputs/DateWidget"; import FileWidget from "./inputs/FileWidget"; -import { useConfig } from "../context/ConfigContext"; -import { useRouterInternal } from "../hooks/useRouterInternal"; -import ActionsDropdown from "./ActionsDropdown"; +import SelectWidget from "./inputs/SelectWidget"; +import Button from "./radix/Button"; +import JsonField from "./inputs/JsonField"; // Override Form functions to not prevent the submit class CustomForm extends RjsfForm { @@ -103,7 +104,7 @@ const Form = ({ )} - + ); }; @@ -232,6 +233,14 @@ const Form = ({ }); } + if (schema?.format === "json") { + return () + } + return ( // @ts-expect-error { +const JsonField = ({ value, onChange, name }: Props) => { const defaultValue = useMemo(() => { try { return JSON.stringify(JSON.parse(value!), null, 2) @@ -34,4 +34,4 @@ const JsonEditor = ({ value, onChange, name }: Props) => { ) } -export default JsonEditor \ No newline at end of file +export default JsonField \ No newline at end of file diff --git a/packages/next-admin/src/types.ts b/packages/next-admin/src/types.ts index 72e6abb8..b7227add 100644 --- a/packages/next-admin/src/types.ts +++ b/packages/next-admin/src/types.ts @@ -77,6 +77,7 @@ export type FormatOptions = T extends string | "alt-datetime" | "alt-date" | "file" + | "json" : never | T extends Date ? "date" | "date-time" | "time" : never | T extends number From 19a10a98182ef2edfb42de929b7768aa329ef9aa Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Thu, 4 Jan 2024 15:33:41 +0100 Subject: [PATCH 4/8] Change dependencies --- apps/example/package.json | 1 - packages/next-admin/package.json | 3 ++- packages/next-admin/src/components/inputs/JsonField.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/example/package.json b/apps/example/package.json index 778b34ba..51445d81 100644 --- a/apps/example/package.json +++ b/apps/example/package.json @@ -18,7 +18,6 @@ }, "dependencies": { "@heroicons/react": "^2.0.18", - "@monaco-editor/react": "^4.6.0", "@picocss/pico": "^1.5.7", "@premieroctet/next-admin": "*", "@prisma/client": "^5.2.0", diff --git a/packages/next-admin/package.json b/packages/next-admin/package.json index 7f9f6ae7..c5133d70 100644 --- a/packages/next-admin/package.json +++ b/packages/next-admin/package.json @@ -12,7 +12,7 @@ "lint": "eslint \"**/*.{ts,tsx}\"", "test": "jest", "test:coverage": "jest --coverage", - "tsc": "tsc --noemit" + "tsc": "tsc --noEmit" }, "peerDependencies": { "@prisma/client": ">=4", @@ -21,6 +21,7 @@ "dependencies": { "@headlessui/react": "^1.7.13", "@heroicons/react": "^2.0.18", + "@monaco-editor/react": "^4.6.0", "@picocss/pico": "^1.5.7", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-select": "^1.2.2", diff --git a/packages/next-admin/src/components/inputs/JsonField.tsx b/packages/next-admin/src/components/inputs/JsonField.tsx index 10b4f81f..569832a3 100644 --- a/packages/next-admin/src/components/inputs/JsonField.tsx +++ b/packages/next-admin/src/components/inputs/JsonField.tsx @@ -1,7 +1,7 @@ import Editor from '@monaco-editor/react'; -import { CustomInputProps } from '@premieroctet/next-admin'; import { useMemo } from 'react'; import * as React from "react"; +import { CustomInputProps } from '../../types'; type Props = CustomInputProps @@ -23,7 +23,7 @@ const JsonField = ({ value, onChange, name }: Props) => { defaultValue={defaultValue} onChange={(val, evt) => { // @ts-expect-error - onChange?.({ target: { value: val ?? "" }}) + onChange?.({ target: { value: val ?? "" } }) }} options={{ minimap: { enabled: false } From c3b875e79df25f64964e778133911ae85ec7a1e2 Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Mon, 12 Feb 2024 14:24:54 +0100 Subject: [PATCH 5/8] Add `@monaco-editor` as optionalDependencies --- .changeset/tricky-frogs-drum.md | 5 +++++ packages/next-admin/package.json | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .changeset/tricky-frogs-drum.md diff --git a/.changeset/tricky-frogs-drum.md b/.changeset/tricky-frogs-drum.md new file mode 100644 index 00000000..602f46f6 --- /dev/null +++ b/.changeset/tricky-frogs-drum.md @@ -0,0 +1,5 @@ +--- +"@premieroctet/next-admin": patch +--- + +Add `@monaco-editor` as optionalDependencies - To use the JSON editor, install the corresponding version of `@monaco-editor/react` diff --git a/packages/next-admin/package.json b/packages/next-admin/package.json index 40783e12..29880b48 100644 --- a/packages/next-admin/package.json +++ b/packages/next-admin/package.json @@ -68,5 +68,8 @@ "ts-node": "^10.9.1", "tsconfig": "*", "tsup": "^6.7.0" + }, +"optionalDependencies": { + "@monaco-editor/react": "^4.6.0" } } From fc6f94c21d062457ec60147b120d982c8290c88d Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Mon, 12 Feb 2024 15:47:28 +0100 Subject: [PATCH 6/8] Remove monaco dependency --- packages/next-admin/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next-admin/package.json b/packages/next-admin/package.json index 29880b48..a601aa4e 100644 --- a/packages/next-admin/package.json +++ b/packages/next-admin/package.json @@ -21,7 +21,6 @@ "dependencies": { "@headlessui/react": "^1.7.13", "@heroicons/react": "^2.0.18", - "@monaco-editor/react": "^4.6.0", "@picocss/pico": "^1.5.7", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-select": "^1.2.2", From 94b0ccc064b8c0edfde989fa9e762fc393cd48b3 Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Mon, 12 Feb 2024 16:07:30 +0100 Subject: [PATCH 7/8] Syntax error --- packages/next-admin/src/components/inputs/JsonField.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-admin/src/components/inputs/JsonField.tsx b/packages/next-admin/src/components/inputs/JsonField.tsx index 976172bd..1719d84a 100644 --- a/packages/next-admin/src/components/inputs/JsonField.tsx +++ b/packages/next-admin/src/components/inputs/JsonField.tsx @@ -1,7 +1,7 @@ +"use client"; import Editor from '@monaco-editor/react'; import { useMemo } from 'react'; import { CustomInputProps } from '../../types'; -"use client"; type Props = CustomInputProps; From a4de91a9532000c32a529beb24bff408176ffcde Mon Sep 17 00:00:00 2001 From: Colin Regourd Date: Mon, 12 Feb 2024 16:12:25 +0100 Subject: [PATCH 8/8] Apply prettier --- .../next-admin/src/components/DataTable.tsx | 10 +- packages/next-admin/src/components/Form.tsx | 13 ++- .../src/components/inputs/JsonField.tsx | 10 +- .../next-admin/src/context/FormContext.tsx | 26 ++--- packages/next-admin/src/types.ts | 94 +++++++++---------- 5 files changed, 79 insertions(+), 74 deletions(-) diff --git a/packages/next-admin/src/components/DataTable.tsx b/packages/next-admin/src/components/DataTable.tsx index f09b3006..6eb98ce7 100644 --- a/packages/next-admin/src/components/DataTable.tsx +++ b/packages/next-admin/src/components/DataTable.tsx @@ -138,9 +138,9 @@ export function DataTable({ {header.isPlaceholder ? null : flexRender( - header.column.columnDef.header, - header.getContext() - )} + header.column.columnDef.header, + header.getContext() + )} ); })} @@ -155,7 +155,9 @@ export function DataTable({ data-state={row.getIsSelected() && "selected"} className="cursor-pointer hover:bg-indigo-50" onClick={() => { - window.location.href = `${basePath}/${resource.toLowerCase()}/${row.original[modelIdProperty].value}` + window.location.href = `${basePath}/${resource.toLowerCase()}/${ + row.original[modelIdProperty].value + }`; }} > {row.getVisibleCells().map((cell) => ( diff --git a/packages/next-admin/src/components/Form.tsx b/packages/next-admin/src/components/Form.tsx index cee21d37..e696da3b 100644 --- a/packages/next-admin/src/components/Form.tsx +++ b/packages/next-admin/src/components/Form.tsx @@ -274,11 +274,14 @@ const Form = ({ } if (schema?.format === "json") { - return () + return ( + + ); } if (schema?.format?.startsWith("richtext-")) { return ( diff --git a/packages/next-admin/src/components/inputs/JsonField.tsx b/packages/next-admin/src/components/inputs/JsonField.tsx index 1719d84a..e29fdc3a 100644 --- a/packages/next-admin/src/components/inputs/JsonField.tsx +++ b/packages/next-admin/src/components/inputs/JsonField.tsx @@ -1,7 +1,7 @@ "use client"; -import Editor from '@monaco-editor/react'; -import { useMemo } from 'react'; -import { CustomInputProps } from '../../types'; +import Editor from "@monaco-editor/react"; +import { useMemo } from "react"; +import { CustomInputProps } from "../../types"; type Props = CustomInputProps; @@ -23,7 +23,7 @@ const JsonField = ({ value, onChange, name }: Props) => { defaultValue={defaultValue} onChange={(val, evt) => { // @ts-expect-error - onChange?.({ target: { value: val ?? "" } }) + onChange?.({ target: { value: val ?? "" } }); }} options={{ minimap: { enabled: false }, @@ -34,4 +34,4 @@ const JsonField = ({ value, onChange, name }: Props) => { ); }; -export default JsonField +export default JsonField; diff --git a/packages/next-admin/src/context/FormContext.tsx b/packages/next-admin/src/context/FormContext.tsx index 8b0d571c..d9f27641 100644 --- a/packages/next-admin/src/context/FormContext.tsx +++ b/packages/next-admin/src/context/FormContext.tsx @@ -14,8 +14,8 @@ type FormContextType = { [P in string]: { open: boolean; selectedValue: - | { value: string; label: string } - | { value: string; label: string }[]; + | { value: string; label: string } + | { value: string; label: string }[]; }; }; setOpen: (open: boolean, name: string) => void; @@ -25,11 +25,11 @@ type FormContextType = { export const FormContext = createContext({ formData: {}, - setFormData: (_formData: any) => { }, + setFormData: (_formData: any) => {}, relationState: {}, - setOpen: (_open: boolean, _name: string) => { }, - setSelectedValue: (_selectedValue: any, _name: string) => { }, - toggleOpen: (_name: string) => { }, + setOpen: (_open: boolean, _name: string) => {}, + setSelectedValue: (_selectedValue: any, _name: string) => {}, + toggleOpen: (_name: string) => {}, }); type Props = PropsWithChildren<{ @@ -40,8 +40,8 @@ type RelationState = { [P in string]: { open: boolean; selectedValue: - | { value: string; label: string } - | { value: string; label: string }[]; + | { value: string; label: string } + | { value: string; label: string }[]; }; }; @@ -52,14 +52,14 @@ export const FormProvider = ({ children, initialValue }: Props) => { const isDirty = !isEqual(initialValue, formData); const onBeforeUnload = (e: any) => { e.preventDefault(); - e.returnValue = true - } + e.returnValue = true; + }; if (isDirty) { - window.addEventListener('beforeunload', onBeforeUnload) + window.addEventListener("beforeunload", onBeforeUnload); } return () => { - window.removeEventListener('beforeunload', onBeforeUnload) - } + window.removeEventListener("beforeunload", onBeforeUnload); + }; }, [formData, initialValue]); const setOpen = (open: boolean, name: string) => { diff --git a/packages/next-admin/src/types.ts b/packages/next-admin/src/types.ts index 8b29a6b0..e876f435 100644 --- a/packages/next-admin/src/types.ts +++ b/packages/next-admin/src/types.ts @@ -24,22 +24,22 @@ export type ModelFromPayload< > = { [Property in keyof P["scalars"]]: P["scalars"][Property]; } & { - [Property in keyof P["objects"]]: P["objects"][Property] extends { - scalars: infer S; - } + [Property in keyof P["objects"]]: P["objects"][Property] extends { + scalars: infer S; + } ? T extends object - ? S - : T + ? S + : T : never | P["objects"][Property] extends { scalars: infer S }[] - ? T extends object - ? S[] - : T[] - : never | P["objects"][Property] extends { scalars: infer S } | null - ? T extends object - ? S | null - : T | null - : never; - }; + ? T extends object + ? S[] + : T[] + : never | P["objects"][Property] extends { scalars: infer S } | null + ? T extends object + ? S | null + : T | null + : never; +}; export type Model< M extends ModelName, @@ -52,10 +52,10 @@ export type PropertyPayload< > = Prisma.TypeMap["model"][M]["payload"]["objects"][P] extends Array ? T : never | Prisma.TypeMap["model"][M]["payload"]["objects"][P] extends - | infer T - | null - ? T - : never | Prisma.TypeMap["model"][M]["payload"]["objects"][P]; + | infer T + | null + ? T + : never | Prisma.TypeMap["model"][M]["payload"]["objects"][P]; export type ModelFromProperty< M extends ModelName, @@ -91,8 +91,8 @@ export type EditFieldsOptions = { input?: React.ReactElement; } & (P extends keyof ObjectField ? { - optionFormatter?: (item: ModelFromProperty) => string; - } + optionFormatter?: (item: ModelFromProperty) => string; + } : {}); }; @@ -109,25 +109,25 @@ export type RichTextFormat = "html" | "json"; export type FormatOptions = T extends string ? - | "textarea" - | "password" - | "color" - | "email" - | "uri" - | "data-url" - | "date" - | "date-time" - | "time" - | "alt-datetime" - | "alt-date" - | "file" - | `richtext-${RichTextFormat}` - | "json" + | "textarea" + | "password" + | "color" + | "email" + | "uri" + | "data-url" + | "date" + | "date-time" + | "time" + | "alt-datetime" + | "alt-date" + | "file" + | `richtext-${RichTextFormat}` + | "json" : never | T extends Date - ? "date" | "date-time" | "time" - : never | T extends number - ? "updown" | "range" - : never; + ? "date" | "date-time" | "time" + : never | T extends number + ? "updown" | "range" + : never; export type ListOptions = { display?: Field[]; @@ -244,16 +244,16 @@ export type ListDataFieldValue = ListDataFieldValueWithFormat & | { type: "scalar"; value: string | number | boolean } | { type: "count"; value: number } | { - type: "link"; - value: { - label: string; - url: string; - }; - } + type: "link"; + value: { + label: string; + url: string; + }; + } | { - type: "date"; - value: Date; - } + type: "date"; + value: Date; + } ); export type AdminComponentProps = {