mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 12:56:05 +00:00
finalize new media settings
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import { Draft2019 } from "json-schema-library";
|
import { Draft2019 } from "json-schema-library";
|
||||||
import type { JSONSchema } from "json-schema-to-ts";
|
import type { JSONSchema } from "json-schema-to-ts";
|
||||||
import * as utils from "../../src/ui/components/form/json-schema-form2/utils";
|
import * as utils from "../../src/ui/components/form/json-schema-form/utils";
|
||||||
|
|
||||||
describe("json form", () => {
|
describe("json form", () => {
|
||||||
test("normalize path", () => {
|
test("normalize path", () => {
|
||||||
@@ -122,7 +122,7 @@ describe("json form", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.only("...", () => {
|
test("...", () => {
|
||||||
const schema = {
|
const schema = {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"fast-xml-parser": "^4.4.0",
|
"fast-xml-parser": "^4.4.0",
|
||||||
"hono": "^4.6.12",
|
"hono": "^4.6.12",
|
||||||
"json-schema-form-react": "link:json-schema-form-react",
|
"json-schema-form-react": "^0.0.2",
|
||||||
"json-schema-library": "^10.0.0-rc7",
|
"json-schema-library": "^10.0.0-rc7",
|
||||||
"kysely": "^0.27.4",
|
"kysely": "^0.27.4",
|
||||||
"liquidjs": "^10.15.0",
|
"liquidjs": "^10.15.0",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type BkndContext = {
|
|||||||
config: ModuleConfigs;
|
config: ModuleConfigs;
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
hasSecrets: boolean;
|
hasSecrets: boolean;
|
||||||
|
fetched: boolean;
|
||||||
requireSecrets: () => Promise<void>;
|
requireSecrets: () => Promise<void>;
|
||||||
actions: ReturnType<typeof getSchemaActions>;
|
actions: ReturnType<typeof getSchemaActions>;
|
||||||
app: AppReduced;
|
app: AppReduced;
|
||||||
@@ -103,7 +104,7 @@ export function BkndProvider({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BkndContext.Provider
|
<BkndContext.Provider
|
||||||
value={{ ...schema, actions, requireSecrets, app, adminOverride, hasSecrets }}
|
value={{ ...schema, fetched, actions, requireSecrets, app, adminOverride, hasSecrets }}
|
||||||
key={local_version}
|
key={local_version}
|
||||||
>
|
>
|
||||||
{/*{error && (
|
{/*{error && (
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
|
import type { TAppMediaConfig } from "media/media-schema";
|
||||||
import { useBknd } from "ui/client/BkndProvider";
|
import { useBknd } from "ui/client/BkndProvider";
|
||||||
|
|
||||||
export function useBkndMedia() {
|
export function useBkndMedia() {
|
||||||
const { config, schema, actions: bkndActions } = useBknd();
|
const { config, schema, actions: bkndActions } = useBknd();
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
/*roles: {
|
config: {
|
||||||
add: async (name: string, data: any = {}) => {
|
patch: async (data: Partial<TAppMediaConfig>) => {
|
||||||
console.log("add role", name, data);
|
return await bkndActions.set("media", data, true);
|
||||||
return await bkndActions.add("auth", `roles.${name}`, data);
|
|
||||||
},
|
|
||||||
patch: async (name: string, data: any) => {
|
|
||||||
console.log("patch role", name, data);
|
|
||||||
return await bkndActions.patch("auth", `roles.${name}`, data);
|
|
||||||
},
|
|
||||||
delete: async (name: string) => {
|
|
||||||
console.log("delete role", name);
|
|
||||||
if (window.confirm(`Are you sure you want to delete the role "${name}"?`)) {
|
|
||||||
return await bkndActions.remove("auth", `roles.${name}`);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
};
|
};
|
||||||
const $media = {};
|
const $media = {};
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const styles = {
|
|||||||
default: "bg-primary/5 hover:bg-primary/10 link text-primary/70",
|
default: "bg-primary/5 hover:bg-primary/10 link text-primary/70",
|
||||||
primary: "bg-primary hover:bg-primary/80 link text-background",
|
primary: "bg-primary hover:bg-primary/80 link text-background",
|
||||||
ghost: "bg-transparent hover:bg-primary/5 link text-primary/70",
|
ghost: "bg-transparent hover:bg-primary/5 link text-primary/70",
|
||||||
outline: "border border-primary/50 bg-transparent hover:bg-primary/5 link text-primary/80",
|
outline: "border border-primary/20 bg-transparent hover:bg-primary/5 link text-primary/80",
|
||||||
red: "dark:bg-red-950 dark:hover:bg-red-900 bg-red-100 hover:bg-red-200 link text-primary/70",
|
red: "dark:bg-red-950 dark:hover:bg-red-900 bg-red-100 hover:bg-red-200 link text-primary/70",
|
||||||
subtlered:
|
subtlered:
|
||||||
"dark:text-red-950 text-red-700 dark:hover:bg-red-900 bg-transparent hover:bg-red-50 link"
|
"dark:text-red-950 text-red-700 dark:hover:bg-red-900 bg-transparent hover:bg-red-50 link"
|
||||||
@@ -51,7 +51,7 @@ const Base = ({
|
|||||||
}: BaseProps) => ({
|
}: BaseProps) => ({
|
||||||
...props,
|
...props,
|
||||||
className: twMerge(
|
className: twMerge(
|
||||||
"flex flex-row flex-nowrap items-center font-semibold disabled:opacity-50 cursor-pointer disabled:cursor-not-allowed",
|
"flex flex-row flex-nowrap items-center font-semibold disabled:opacity-50 cursor-pointer disabled:cursor-not-allowed transition-[opacity,background-color,color,border-color]",
|
||||||
sizes[size ?? "default"],
|
sizes[size ?? "default"],
|
||||||
styles[variant ?? "default"],
|
styles[variant ?? "default"],
|
||||||
props.className
|
props.className
|
||||||
|
|||||||
@@ -38,10 +38,11 @@ export const Field = ({ name, schema: _schema, onChange, label: _label, hidden }
|
|||||||
setValue(pointer, value as any);*/
|
setValue(pointer, value as any);*/
|
||||||
|
|
||||||
const value = coerce(e.target.value, schema as any, { required });
|
const value = coerce(e.target.value, schema as any, { required });
|
||||||
//console.log("handleChange", pointer, e.target.value, { value });
|
//console.log("handleChange", pointer, e.target.value, { value }, ctx.options);
|
||||||
if (typeof value === "undefined" && !required) {
|
if (typeof value === "undefined" && !required && ctx.options?.keepEmpty !== true) {
|
||||||
ctx.deleteValue(pointer);
|
ctx.deleteValue(pointer);
|
||||||
} else {
|
} else {
|
||||||
|
//console.log("setValue", pointer, value);
|
||||||
setValue(pointer, value);
|
setValue(pointer, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Popover } from "@mantine/core";
|
|||||||
import { IconBug } from "@tabler/icons-react";
|
import { IconBug } from "@tabler/icons-react";
|
||||||
import type { JsonError } from "json-schema-library";
|
import type { JsonError } from "json-schema-library";
|
||||||
import type { JSONSchema } from "json-schema-to-ts";
|
import type { JSONSchema } from "json-schema-to-ts";
|
||||||
import { Children, type ReactElement, type ReactNode, cloneElement } from "react";
|
import { Children, type ReactElement, type ReactNode, cloneElement, isValidElement } from "react";
|
||||||
import { IconButton } from "ui/components/buttons/IconButton";
|
import { IconButton } from "ui/components/buttons/IconButton";
|
||||||
import { JsonViewer } from "ui/components/code/JsonViewer";
|
import { JsonViewer } from "ui/components/code/JsonViewer";
|
||||||
import * as Formy from "ui/components/form/Formy";
|
import * as Formy from "ui/components/form/Formy";
|
||||||
@@ -14,7 +14,7 @@ export type FieldwrapperProps = {
|
|||||||
required?: boolean;
|
required?: boolean;
|
||||||
errors?: JsonError[];
|
errors?: JsonError[];
|
||||||
schema?: Exclude<JSONSchema, boolean>;
|
schema?: Exclude<JSONSchema, boolean>;
|
||||||
debug?: object;
|
debug?: object | boolean;
|
||||||
wrapper?: "group" | "fieldset";
|
wrapper?: "group" | "fieldset";
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
children: ReactElement | ReactNode;
|
children: ReactElement | ReactNode;
|
||||||
@@ -26,7 +26,7 @@ export function FieldWrapper({
|
|||||||
required,
|
required,
|
||||||
errors = [],
|
errors = [],
|
||||||
schema,
|
schema,
|
||||||
debug = {},
|
debug,
|
||||||
wrapper,
|
wrapper,
|
||||||
hidden,
|
hidden,
|
||||||
children
|
children
|
||||||
@@ -43,20 +43,28 @@ export function FieldWrapper({
|
|||||||
as={wrapper === "fieldset" ? "fieldset" : "div"}
|
as={wrapper === "fieldset" ? "fieldset" : "div"}
|
||||||
className={hidden ? "hidden" : "relative"}
|
className={hidden ? "hidden" : "relative"}
|
||||||
>
|
>
|
||||||
{/*<div className="absolute right-0 top-0">
|
{debug && (
|
||||||
<Popover>
|
<div className="absolute right-0 top-0">
|
||||||
<Popover.Target>
|
<Popover>
|
||||||
<IconButton Icon={IconBug} size="xs" className="opacity-30" />
|
<Popover.Target>
|
||||||
</Popover.Target>
|
<IconButton Icon={IconBug} size="xs" className="opacity-30" />
|
||||||
<Popover.Dropdown>
|
</Popover.Target>
|
||||||
<JsonViewer
|
<Popover.Dropdown>
|
||||||
json={{ ...debug, pointer, required, schema, errors }}
|
<JsonViewer
|
||||||
expand={6}
|
json={{
|
||||||
className="p-0"
|
...(typeof debug === "object" ? debug : {}),
|
||||||
/>
|
pointer,
|
||||||
</Popover.Dropdown>
|
required,
|
||||||
</Popover>
|
schema,
|
||||||
</div>*/}
|
errors
|
||||||
|
}}
|
||||||
|
expand={6}
|
||||||
|
className="p-0"
|
||||||
|
/>
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{label && (
|
{label && (
|
||||||
<Formy.Label as={wrapper === "fieldset" ? "legend" : "label"} htmlFor={pointer}>
|
<Formy.Label as={wrapper === "fieldset" ? "legend" : "label"} htmlFor={pointer}>
|
||||||
@@ -65,9 +73,9 @@ export function FieldWrapper({
|
|||||||
)}
|
)}
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<div className="flex flex-1 flex-col gap-3">
|
<div className="flex flex-1 flex-col gap-3">
|
||||||
{children}
|
{Children.count(children) === 1 && isValidElement(children)
|
||||||
{/*{Children.count(children) === 1
|
|
||||||
? cloneElement(children, {
|
? cloneElement(children, {
|
||||||
|
// @ts-ignore
|
||||||
list: examples.length > 0 ? examplesId : undefined
|
list: examples.length > 0 ? examplesId : undefined
|
||||||
})
|
})
|
||||||
: children}
|
: children}
|
||||||
@@ -77,7 +85,7 @@ export function FieldWrapper({
|
|||||||
<option key={i} value={e as any} />
|
<option key={i} value={e as any} />
|
||||||
))}
|
))}
|
||||||
</datalist>
|
</datalist>
|
||||||
)}*/}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{description && <Formy.Help>{description}</Formy.Help>}
|
{description && <Formy.Help>{description}</Formy.Help>}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import { JsonViewer } from "ui/components/code/JsonViewer";
|
||||||
import { Field } from "./Field";
|
import { Field } from "./Field";
|
||||||
import { isRequired, normalizePath, omitSchema, prefixPointer } from "./utils";
|
import { isRequired, normalizePath, omitSchema, prefixPointer } from "./utils";
|
||||||
|
|
||||||
@@ -32,6 +33,10 @@ export type FormProps<
|
|||||||
onSubmit?: (data: Partial<Data>) => void | Promise<void>;
|
onSubmit?: (data: Partial<Data>) => void | Promise<void>;
|
||||||
onInvalidSubmit?: (errors: JsonError[], data: Partial<Data>) => void;
|
onInvalidSubmit?: (errors: JsonError[], data: Partial<Data>) => void;
|
||||||
hiddenSubmit?: boolean;
|
hiddenSubmit?: boolean;
|
||||||
|
options?: {
|
||||||
|
debug?: boolean;
|
||||||
|
keepEmpty?: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FormContext<Data> = {
|
export type FormContext<Data> = {
|
||||||
@@ -44,6 +49,7 @@ export type FormContext<Data> = {
|
|||||||
submitting: boolean;
|
submitting: boolean;
|
||||||
schema: JSONSchema;
|
schema: JSONSchema;
|
||||||
lib: Draft2019;
|
lib: Draft2019;
|
||||||
|
options: FormProps["options"];
|
||||||
};
|
};
|
||||||
|
|
||||||
const FormContext = createContext<FormContext<any>>(undefined!);
|
const FormContext = createContext<FormContext<any>>(undefined!);
|
||||||
@@ -62,6 +68,7 @@ export function Form<
|
|||||||
validateOn = "submit",
|
validateOn = "submit",
|
||||||
hiddenSubmit = true,
|
hiddenSubmit = true,
|
||||||
ignoreKeys = [],
|
ignoreKeys = [],
|
||||||
|
options = {},
|
||||||
...props
|
...props
|
||||||
}: FormProps<Schema, Data>) {
|
}: FormProps<Schema, Data>) {
|
||||||
const [schema, initial] = omitSchema(_schema, ignoreKeys, _initialValues);
|
const [schema, initial] = omitSchema(_schema, ignoreKeys, _initialValues);
|
||||||
@@ -146,7 +153,8 @@ export function Form<
|
|||||||
deleteValue,
|
deleteValue,
|
||||||
errors,
|
errors,
|
||||||
schema,
|
schema,
|
||||||
lib
|
lib,
|
||||||
|
options
|
||||||
} as any;
|
} as any;
|
||||||
//console.log("context", context);
|
//console.log("context", context);
|
||||||
|
|
||||||
@@ -229,3 +237,10 @@ export function Subscribe({ children }: { children: (ctx: FormContext<any>) => R
|
|||||||
const ctx = useFormContext();
|
const ctx = useFormContext();
|
||||||
return children(ctx);
|
return children(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function FormDebug() {
|
||||||
|
const { options, data, dirty, errors, submitting } = useFormContext();
|
||||||
|
if (options?.debug !== true) return null;
|
||||||
|
|
||||||
|
return <JsonViewer json={{ dirty, submitting, data, errors }} expand={99} />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,33 +1,17 @@
|
|||||||
import { IconPhoto } from "@tabler/icons-react";
|
import { IconAlertHexagon } from "@tabler/icons-react";
|
||||||
import { TbSettings } from "react-icons/tb";
|
import { TbSettings } from "react-icons/tb";
|
||||||
import { useBknd } from "ui/client/BkndProvider";
|
import { useBknd } from "ui/client/BkndProvider";
|
||||||
import { IconButton } from "ui/components/buttons/IconButton";
|
import { IconButton } from "ui/components/buttons/IconButton";
|
||||||
import { Empty } from "ui/components/display/Empty";
|
|
||||||
import { Link } from "ui/components/wouter/Link";
|
import { Link } from "ui/components/wouter/Link";
|
||||||
import { Media } from "ui/elements";
|
import { Media } from "ui/elements";
|
||||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||||
import { useLocation } from "wouter";
|
|
||||||
|
|
||||||
export function MediaRoot({ children }) {
|
export function MediaRoot({ children }) {
|
||||||
const { app, config } = useBknd();
|
const { app, config } = useBknd();
|
||||||
const [, navigate] = useLocation();
|
const mediaDisabled = !config.media.enabled;
|
||||||
useBrowserTitle(["Media"]);
|
useBrowserTitle(["Media"]);
|
||||||
|
|
||||||
if (!config.media.enabled) {
|
|
||||||
return (
|
|
||||||
<Empty
|
|
||||||
Icon={IconPhoto}
|
|
||||||
title="Media not enabled"
|
|
||||||
description="Please enable media in the settings to continue."
|
|
||||||
primary={{
|
|
||||||
children: "Manage Settings",
|
|
||||||
onClick: () => navigate(app.getSettingsPath(["media"]))
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AppShell.Sidebar>
|
<AppShell.Sidebar>
|
||||||
@@ -42,12 +26,13 @@ export function MediaRoot({ children }) {
|
|||||||
</AppShell.SectionHeader>
|
</AppShell.SectionHeader>
|
||||||
<AppShell.Scrollable initialOffset={96}>
|
<AppShell.Scrollable initialOffset={96}>
|
||||||
<div className="flex flex-col flex-grow p-3 gap-3">
|
<div className="flex flex-col flex-grow p-3 gap-3">
|
||||||
{/*<div>
|
|
||||||
<SearchInput placeholder="Search buckets" />
|
|
||||||
</div>*/}
|
|
||||||
<nav className="flex flex-col flex-1 gap-1">
|
<nav className="flex flex-col flex-1 gap-1">
|
||||||
<AppShell.SidebarLink as={Link} href={"/"}>
|
<AppShell.SidebarLink
|
||||||
Main Bucket
|
as={Link}
|
||||||
|
href={"/"}
|
||||||
|
className="flex flex-row justify-between"
|
||||||
|
>
|
||||||
|
Main Bucket {mediaDisabled && <IconAlertHexagon className="size-5" />}
|
||||||
</AppShell.SidebarLink>
|
</AppShell.SidebarLink>
|
||||||
<AppShell.SidebarLink as={Link} href={"/settings"}>
|
<AppShell.SidebarLink as={Link} href={"/settings"}>
|
||||||
Settings
|
Settings
|
||||||
|
|||||||
@@ -1,10 +1,30 @@
|
|||||||
|
import { IconPhoto } from "@tabler/icons-react";
|
||||||
|
import { useBknd } from "ui/client/BkndProvider";
|
||||||
|
import { Empty } from "ui/components/display/Empty";
|
||||||
import { Media } from "ui/elements";
|
import { Media } from "ui/elements";
|
||||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||||
|
import { useLocation } from "wouter";
|
||||||
|
|
||||||
export function MediaIndex() {
|
export function MediaIndex() {
|
||||||
|
const { app, config } = useBknd();
|
||||||
|
const [, navigate] = useLocation();
|
||||||
useBrowserTitle(["Media"]);
|
useBrowserTitle(["Media"]);
|
||||||
|
|
||||||
|
if (!config.media.enabled) {
|
||||||
|
return (
|
||||||
|
<Empty
|
||||||
|
Icon={IconPhoto}
|
||||||
|
title="Media not enabled"
|
||||||
|
description="Please enable media in the settings to continue."
|
||||||
|
primary={{
|
||||||
|
children: "Manage Settings",
|
||||||
|
onClick: () => navigate("/settings")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppShell.Scrollable>
|
<AppShell.Scrollable>
|
||||||
<div className="flex flex-1 p-3">
|
<div className="flex flex-1 p-3">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { IconBrandAws, IconCloud, IconServer } from "@tabler/icons-react";
|
import { IconBrandAws, IconCloud, IconServer } from "@tabler/icons-react";
|
||||||
|
import { isDebug } from "core";
|
||||||
import { autoFormatString } from "core/utils";
|
import { autoFormatString } from "core/utils";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
import { useBknd } from "ui/client/BkndProvider";
|
import { useBknd } from "ui/client/BkndProvider";
|
||||||
@@ -11,6 +12,7 @@ import {
|
|||||||
Field,
|
Field,
|
||||||
Form,
|
Form,
|
||||||
FormContextOverride,
|
FormContextOverride,
|
||||||
|
FormDebug,
|
||||||
ObjectField,
|
ObjectField,
|
||||||
Subscribe
|
Subscribe
|
||||||
} from "ui/components/form/json-schema-form";
|
} from "ui/components/form/json-schema-form";
|
||||||
@@ -29,24 +31,23 @@ export function MediaSettings(props) {
|
|||||||
return <MediaSettingsInternal {...props} />;
|
return <MediaSettingsInternal {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ignore = ["entity_name", "basepath"];
|
const formConfig = {
|
||||||
|
ignoreKeys: ["entity_name", "basepath"],
|
||||||
|
options: { debug: isDebug(), keepEmpty: true }
|
||||||
|
};
|
||||||
|
|
||||||
function MediaSettingsInternal() {
|
function MediaSettingsInternal() {
|
||||||
const { config, schema } = useBkndMedia();
|
const { config, schema, actions } = useBkndMedia();
|
||||||
|
|
||||||
async function onSubmit(data: any) {
|
async function onSubmit(data: any) {
|
||||||
console.log("submit", data);
|
console.log("submit", data);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await actions.config.patch(data);
|
||||||
|
//await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form
|
<Form schema={schema} initialValues={config as any} onSubmit={onSubmit} {...formConfig}>
|
||||||
schema={schema}
|
|
||||||
initialValues={config as any}
|
|
||||||
ignoreKeys={ignore}
|
|
||||||
onSubmit={onSubmit}
|
|
||||||
noValidate
|
|
||||||
>
|
|
||||||
<Subscribe>
|
<Subscribe>
|
||||||
{({ dirty, errors, submitting }) => (
|
{({ dirty, errors, submitting }) => (
|
||||||
<AppShell.SectionHeader
|
<AppShell.SectionHeader
|
||||||
@@ -79,11 +80,7 @@ function MediaSettingsInternal() {
|
|||||||
<Adapters />
|
<Adapters />
|
||||||
</AnyOf.Root>
|
</AnyOf.Root>
|
||||||
</div>
|
</div>
|
||||||
{/*<Subscribe>
|
<FormDebug />
|
||||||
{({ data, errors }) => (
|
|
||||||
<JsonViewer json={JSON.parse(JSON.stringify({ data, errors }))} expand={999} />
|
|
||||||
)}
|
|
||||||
</Subscribe>*/}
|
|
||||||
</AppShell.Scrollable>
|
</AppShell.Scrollable>
|
||||||
</Form>
|
</Form>
|
||||||
</>
|
</>
|
||||||
@@ -105,7 +102,7 @@ function Adapters() {
|
|||||||
<Formy.Group>
|
<Formy.Group>
|
||||||
<Formy.Label className="flex flex-row items-center gap-1">
|
<Formy.Label className="flex flex-row items-center gap-1">
|
||||||
<span className="font-bold">Media Adapter:</span>
|
<span className="font-bold">Media Adapter:</span>
|
||||||
{!ctx.selected && <span className="opacity-70"> (Choose one)</span>}
|
{ctx.selected === null && <span className="opacity-70"> (Choose one)</span>}
|
||||||
</Formy.Label>
|
</Formy.Label>
|
||||||
<div className="flex flex-row gap-1 mb-2">
|
<div className="flex flex-row gap-1 mb-2">
|
||||||
{ctx.schemas?.map((schema: any, i) => (
|
{ctx.schemas?.map((schema: any, i) => (
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export default function JsonSchemaFormReactTest() {
|
|||||||
<>
|
<>
|
||||||
<Form
|
<Form
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onChange={setData}
|
/*onChange={setData}
|
||||||
onSubmit={setData}
|
onSubmit={setData}*/
|
||||||
validator={validator}
|
validator={validator}
|
||||||
validationMode="change"
|
validationMode="change"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user