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:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user