fix json field form, replaced auth form

This commit is contained in:
dswbx
2025-07-09 08:13:32 +02:00
parent 9d5bc61f33
commit 2ca1f64ae6
6 changed files with 68 additions and 69 deletions
+2 -3
View File
@@ -60,8 +60,7 @@
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"fast-xml-parser": "^5.0.8", "fast-xml-parser": "^5.0.8",
"hono": "^4.7.11", "hono": "4.8.3",
"json-schema-form-react": "^0.0.2",
"json-schema-library": "10.0.0-rc7", "json-schema-library": "10.0.0-rc7",
"json-schema-to-ts": "^3.1.1", "json-schema-to-ts": "^3.1.1",
"kysely": "^0.27.6", "kysely": "^0.27.6",
@@ -100,7 +99,7 @@
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"jotai": "^2.12.2", "jotai": "^2.12.2",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
"jsonv-ts": "^0.2.2", "jsonv-ts": "link:jsonv-ts",
"kysely-d1": "^0.3.0", "kysely-d1": "^0.3.0",
"kysely-generic-sqlite": "^1.2.1", "kysely-generic-sqlite": "^1.2.1",
"libsql-stateless-easy": "^1.8.0", "libsql-stateless-easy": "^1.8.0",
+6 -2
View File
@@ -1,5 +1,5 @@
import type { PrimaryFieldType } from "core"; import type { PrimaryFieldType } from "core";
import { $console } from "core/utils"; import { $console, isPlainObject } from "core/utils";
import { isDebug } from "core/env"; import { isDebug } from "core/env";
import { encodeSearch } from "core/utils/reqres"; import { encodeSearch } from "core/utils/reqres";
import type { ApiFetcher } from "Api"; import type { ApiFetcher } from "Api";
@@ -95,7 +95,11 @@ export abstract class ModuleApi<Options extends BaseModuleApiOptions = BaseModul
let body: any = _init?.body; let body: any = _init?.body;
if (_init && "body" in _init && ["POST", "PATCH", "PUT"].includes(method)) { if (_init && "body" in _init && ["POST", "PATCH", "PUT"].includes(method)) {
const requestContentType = (headers.get("Content-Type") as string) ?? undefined; const requestContentType = (headers.get("Content-Type") as string) ?? undefined;
if (!requestContentType || requestContentType.startsWith("application/json")) { if (
!requestContentType ||
requestContentType.startsWith("application/json") ||
isPlainObject(body) // @todo: not entirely sure about this
) {
body = JSON.stringify(_init.body); body = JSON.stringify(_init.body);
headers.set("Content-Type", "application/json"); headers.set("Content-Type", "application/json");
} }
@@ -34,11 +34,13 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
private renderFallback() { private renderFallback() {
if (this.props.fallback) { if (this.props.fallback) {
return typeof this.props.fallback === "function" return typeof this.props.fallback === "function" ? (
? this.props.fallback({ error: this.state.error!, resetError: this.resetError }) this.props.fallback({ error: this.state.error!, resetError: this.resetError })
: this.props.fallback; ) : (
<BaseError>{this.props.fallback}</BaseError>
);
} }
return <BaseError>Error</BaseError>; return <BaseError>Error1</BaseError>;
} }
override render() { override render() {
@@ -6,7 +6,6 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import { useEvent } from "ui/hooks/use-event";
import { import {
type CleanOptions, type CleanOptions,
type InputElement, type InputElement,
+20 -46
View File
@@ -1,20 +1,11 @@
import type { AppAuthOAuthStrategy, AppAuthSchema } from "auth/auth-schema"; import type { AppAuthOAuthStrategy, AppAuthSchema } from "auth/auth-schema";
import clsx from "clsx"; import clsx from "clsx";
import { Form } from "json-schema-form-react"; import { NativeForm } from "ui/components/form/native-form/NativeForm";
import { transform } from "lodash-es"; import { transform } from "lodash-es";
import type { ComponentPropsWithoutRef } from "react"; import type { ComponentPropsWithoutRef } from "react";
import { Button } from "ui/components/buttons/Button"; import { Button } from "ui/components/buttons/Button";
import { Group, Input, Password, Label } from "ui/components/form/Formy/components"; import { Group, Input, Password, Label } from "ui/components/form/Formy/components";
import { SocialLink } from "./SocialLink"; import { SocialLink } from "./SocialLink";
import type { Validator } from "json-schema-form-react";
import { s } from "bknd/core";
import type { ErrorDetail } from "jsonv-ts";
class JsonvTsValidator implements Validator<ErrorDetail> {
async validate(schema: s.Schema, data: any) {
return schema.validate(data).errors;
}
}
export type LoginFormProps = Omit<ComponentPropsWithoutRef<"form">, "onSubmit" | "action"> & { export type LoginFormProps = Omit<ComponentPropsWithoutRef<"form">, "onSubmit" | "action"> & {
className?: string; className?: string;
@@ -25,16 +16,6 @@ export type LoginFormProps = Omit<ComponentPropsWithoutRef<"form">, "onSubmit" |
buttonLabel?: string; buttonLabel?: string;
}; };
const validator = new JsonvTsValidator();
const schema = s.strictObject({
email: s.string({
pattern: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$",
}),
password: s.string({
minLength: 8, // @todo: this should be configurable
}),
});
export function AuthForm({ export function AuthForm({
formData, formData,
className, className,
@@ -79,38 +60,31 @@ export function AuthForm({
<Or /> <Or />
</> </>
)} )}
<Form <NativeForm
method={method} method={method}
action={password.action} action={password.action}
{...(props as any)} {...(props as any)}
schema={schema} validateOn="change"
validator={validator}
validationMode="change"
className={clsx("flex flex-col gap-3 w-full", className)} className={clsx("flex flex-col gap-3 w-full", className)}
> >
{({ errors, submitting }) => ( <Group>
<> <Label htmlFor="email">Email address</Label>
<Group> <Input type="email" name="email" required />
<Label htmlFor="email">Email address</Label> </Group>
<Input type="email" name="email" /> <Group>
</Group> <Label htmlFor="password">Password</Label>
<Group> <Password name="password" required minLength={8} />
<Label htmlFor="password">Password</Label> </Group>
<Password name="password" />
</Group>
<Button <Button
type="submit" type="submit"
variant="primary" variant="primary"
size="large" size="large"
className="w-full mt-2 justify-center" className="w-full mt-2 justify-center"
disabled={errors.length > 0 || submitting} >
> {buttonLabel}
{buttonLabel} </Button>
</Button> </NativeForm>
</>
)}
</Form>
</div> </div>
); );
} }
@@ -23,6 +23,7 @@ import { MantineSelect } from "ui/components/form/hook-form-mantine/MantineSelec
import type { TPrimaryFieldFormat } from "data/fields/PrimaryField"; import type { TPrimaryFieldFormat } from "data/fields/PrimaryField";
import { s, stringIdentifier } from "bknd/core"; import { s, stringIdentifier } from "bknd/core";
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"; import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
import ErrorBoundary from "ui/components/display/ErrorBoundary";
const fieldsSchemaObject = originalFieldsSchemaObject; const fieldsSchemaObject = originalFieldsSchemaObject;
const fieldsSchema = s.anyOf(Object.values(fieldsSchemaObject)); const fieldsSchema = s.anyOf(Object.values(fieldsSchemaObject));
@@ -453,19 +454,17 @@ function EntityField({
</Tabs.Panel> </Tabs.Panel>
<Tabs.Panel value="specific"> <Tabs.Panel value="specific">
<div className="flex flex-col gap-2 pt-3 pb-1"> <div className="flex flex-col gap-2 pt-3 pb-1">
<JsonSchemaForm <ErrorBoundary fallback={`Error rendering JSON Schema for ${type}`}>
key={type} <SpecificForm
schema={specificFieldSchema(type as any)} field={field}
formData={specificData} onChange={(value) => {
uiSchema={dataFieldsUiSchema.config} setValue(`${prefix}.config`, {
className="legacy hide-required-mark fieldset-alternative mute-root" ...getValues([`fields.${index}.config`])[0],
onChange={(value) => { ...value,
setValue(`${prefix}.config`, { });
...getValues([`fields.${index}.config`])[0], }}
...value, />
}); </ErrorBoundary>
}}
/>
</div> </div>
</Tabs.Panel> </Tabs.Panel>
<Tabs.Panel value="code"> <Tabs.Panel value="code">
@@ -490,3 +489,25 @@ function EntityField({
</div> </div>
); );
} }
const SpecificForm = ({
field,
onChange,
}: {
field: FieldArrayWithId<TFieldsFormSchema, "fields", "id">;
onChange: (value: any) => void;
}) => {
const type = field.field.type;
const specificData = omit(field.field.config, commonProps);
return (
<JsonSchemaForm
key={type}
schema={specificFieldSchema(type as any)?.toJSON()}
formData={specificData}
uiSchema={dataFieldsUiSchema.config}
className="legacy hide-required-mark fieldset-alternative mute-root"
onChange={onChange}
/>
);
};