Merge pull request 'UI: improve dynamic module interface rendering' (#2269) from hsjobeki/clan-core:hsjobeki-main into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/2269
This commit is contained in:
hsjobeki
2024-10-22 13:30:33 +00:00

View File

@@ -1,14 +1,22 @@
import { callApi, SuccessData } from "@/src/api"; import { callApi } from "@/src/api";
import { activeURI } from "@/src/App"; import { activeURI } from "@/src/App";
import { BackButton } from "@/src/components/BackButton"; import { BackButton } from "@/src/components/BackButton";
import { createModulesQuery } from "@/src/queries"; import { createModulesQuery } from "@/src/queries";
import { useParams } from "@solidjs/router"; import { useParams } from "@solidjs/router";
import { createEffect, For, Match, Show, Switch } from "solid-js"; import {
createEffect,
createSignal,
For,
JSX,
Match,
Show,
Switch,
} from "solid-js";
import { SolidMarkdown } from "solid-markdown"; import { SolidMarkdown } from "solid-markdown";
import toast from "solid-toast"; import toast from "solid-toast";
import { ModuleInfo } from "./list"; import { ModuleInfo } from "./list";
import { createQuery } from "@tanstack/solid-query"; import { createQuery } from "@tanstack/solid-query";
import { JSONSchema4 } from "json-schema"; import { JSONSchema7 } from "json-schema";
import { TextInput } from "@/src/components/TextInput"; import { TextInput } from "@/src/components/TextInput";
import { import {
createForm, createForm,
@@ -53,7 +61,6 @@ function deepMerge(
} }
} }
} }
return result; return result;
} }
@@ -118,9 +125,9 @@ const Details = (props: DetailsProps) => {
); );
}; };
type ModuleSchemasType = Record<string, Record<string, JSONSchema4>>; type ModuleSchemasType = Record<string, Record<string, JSONSchema7>>;
const Unsupported = (props: { schema: JSONSchema4; what: string }) => ( const Unsupported = (props: { schema: JSONSchema7; what: string }) => (
<div> <div>
Cannot render {props.what} Cannot render {props.what}
<pre> <pre>
@@ -138,7 +145,7 @@ function removeTrailingS(str: string) {
} }
interface SchemaFormProps { interface SchemaFormProps {
title: string; title: string;
schema: JSONSchema4; schema: JSONSchema7;
path: string[]; path: string[];
} }
@@ -167,6 +174,14 @@ export const ModuleForm = (props: { id: string }) => {
) => { ) => {
console.log("Submitted form values", values); console.log("Submitted form values", values);
}; };
const [newKey, setNewKey] = createSignal<string>("");
const handleChangeKey: JSX.ChangeEventHandler<HTMLInputElement, Event> = (
e,
) => {
setNewKey(e.currentTarget.value);
};
const SchemaForm = (props: SchemaFormProps) => { const SchemaForm = (props: SchemaFormProps) => {
return ( return (
<div> <div>
@@ -185,11 +200,17 @@ export const ModuleForm = (props: { id: string }) => {
{(properties) => ( {(properties) => (
<For each={Object.entries(properties())}> <For each={Object.entries(properties())}>
{([key, value]) => ( {([key, value]) => (
<SchemaForm <Switch fallback={`Cannot render sub-schema of ${value}`}>
title={key} <Match when={typeof value === "object" && value}>
schema={value} {(sub) => (
path={[...props.path, key]} <SchemaForm
/> title={key}
schema={sub()}
path={[...props.path, key]}
/>
)}
</Match>
</Switch>
)} )}
</For> </For>
)} )}
@@ -229,19 +250,44 @@ export const ModuleForm = (props: { id: string }) => {
)} )}
</For> </For>
</Show> </Show>
<input
value={newKey()}
onChange={handleChangeKey}
type={"text"}
placeholder={`Name of ${removeTrailingS(props.title)}`}
required
/>
<button <button
class="btn btn-ghost" class="btn btn-ghost"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
const value = getValue(formStore, props.title); const value = getValue(formStore, props.title);
setValue(formStore, props.title, { if (!newKey()) return;
// @ts-expect-error: TODO: check to be an object
...value, if (value === undefined) {
foo: {}, setValue(formStore, props.title, {
}); [newKey()]: {},
});
setNewKey("");
} else if (
typeof value === "object" &&
value !== null &&
!(newKey() in value)
) {
setValue(formStore, props.title, {
...value,
[newKey()]: {},
});
setNewKey("");
} else {
console.debug(
"Unsupported key value pair. (attrsOf t)",
{ value },
);
}
}} }}
> >
Add Add new {removeTrailingS(props.title)}
</button> </button>
</> </>
)} )}
@@ -264,7 +310,12 @@ export const ModuleForm = (props: { id: string }) => {
label={props.title} label={props.title}
// @ts-expect-error: It is a string, otherwise the json schema would be invalid // @ts-expect-error: It is a string, otherwise the json schema would be invalid
value={field.value ?? ""} value={field.value ?? ""}
placeholder={`${props.schema.default || ""}`.replace(
"\u2039name\u203a",
`${props.path.at(-2)}`,
)}
error={field.error} error={field.error}
required={!props.schema.default}
/> />
)} )}
</Field> </Field>