forked from pinks/eris
275 lines
8.7 KiB
TypeScript
275 lines
8.7 KiB
TypeScript
import { cx } from "@twind/core";
|
|
import React, { ReactNode, useState } from "react";
|
|
import useSWR from "swr";
|
|
import { fetchApi, handleResponse } from "./apiClient.tsx";
|
|
|
|
export function SettingsPage(props: { sessionId: string }) {
|
|
const { sessionId } = props;
|
|
const session = useSWR(
|
|
sessionId ? ["sessions/{sessionId}", "GET", { params: { sessionId } }] as const : null,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const user = useSWR(
|
|
session.data?.userId
|
|
? ["users/{userId}", "GET", { params: { userId: String(session.data.userId) } }] as const
|
|
: null,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const params = useSWR(
|
|
["settings/params", "GET", {}] as const,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const [changedParams, setChangedParams] = useState<Partial<typeof params.data>>({});
|
|
const [error, setError] = useState<string>();
|
|
|
|
return (
|
|
<form
|
|
className="flex flex-col items-stretch gap-4"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
params.mutate(() =>
|
|
fetchApi("settings/params", "PATCH", {
|
|
query: { sessionId },
|
|
body: { type: "application/json", data: changedParams ?? {} },
|
|
}).then(handleResponse)
|
|
)
|
|
.then(() => setChangedParams({}))
|
|
.catch((e) => setError(String(e)));
|
|
}}
|
|
>
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Negative prompt {changedParams?.negative_prompt != null ? "(Changed)" : ""}
|
|
</span>
|
|
<textarea
|
|
className="input-text"
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.negative_prompt ??
|
|
params.data?.negative_prompt ??
|
|
""}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
negative_prompt: e.target.value,
|
|
}))}
|
|
/>
|
|
</label>
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Sampler {changedParams?.sampler_name != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.sampler_name ??
|
|
params.data?.sampler_name ??
|
|
""}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
sampler_name: e.target.value,
|
|
}))}
|
|
/>
|
|
</label>
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Steps {changedParams?.steps != null ? "(Changed)" : ""}
|
|
</span>
|
|
<span className="flex items-center gap-1">
|
|
<input
|
|
className="input-text w-20"
|
|
type="number"
|
|
min={5}
|
|
max={50}
|
|
step={5}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.steps ??
|
|
params.data?.steps ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
steps: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range flex-grow"
|
|
type="range"
|
|
min={5}
|
|
max={50}
|
|
step={5}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.steps ??
|
|
params.data?.steps ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
steps: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</span>
|
|
</label>
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Detail {changedParams?.cfg_scale != null ? "(Changed)" : ""}
|
|
</span>
|
|
<span className="flex items-center gap-1">
|
|
<input
|
|
className="input-text w-20"
|
|
type="number"
|
|
min={1}
|
|
max={20}
|
|
step={1}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.cfg_scale ??
|
|
params.data?.cfg_scale ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
cfg_scale: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range flex-grow"
|
|
type="range"
|
|
min={1}
|
|
max={20}
|
|
step={1}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.cfg_scale ??
|
|
params.data?.cfg_scale ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
cfg_scale: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</span>
|
|
</label>
|
|
<div className="flex gap-4">
|
|
<label className="flex flex-1 flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Width {changedParams?.width != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
type="number"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.width ??
|
|
params.data?.width ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
width: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range"
|
|
type="range"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.width ??
|
|
params.data?.width ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
width: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</label>
|
|
<label className="flex flex-1 flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Height {changedParams?.height != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
type="number"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.height ??
|
|
params.data?.height ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
height: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range"
|
|
type="range"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={params.isLoading || !user.data?.isAdmin}
|
|
value={changedParams?.height ??
|
|
params.data?.height ??
|
|
0}
|
|
onChange={(e) =>
|
|
setChangedParams((params) => ({
|
|
...params,
|
|
height: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</label>
|
|
</div>
|
|
{error ? <Alert onClose={() => setError(undefined)}>{error}</Alert> : null}
|
|
{params.error ? <Alert>{params.error.message}</Alert> : null}
|
|
<div className="flex gap-2 items-center justify-end">
|
|
<button
|
|
type="button"
|
|
className={cx("button-outlined ripple", params.isLoading && "bg-stripes")}
|
|
disabled={params.isLoading || !user.data?.isAdmin ||
|
|
Object.keys(changedParams ?? {}).length === 0}
|
|
onClick={() => setChangedParams({})}
|
|
>
|
|
Reset
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className={cx("button-filled ripple", params.isLoading && "bg-stripes")}
|
|
disabled={params.isLoading || !user.data?.isAdmin ||
|
|
Object.keys(changedParams ?? {}).length === 0}
|
|
>
|
|
Save
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
function Alert(props: { children: ReactNode; onClose?: () => void }) {
|
|
const { children, onClose } = props;
|
|
return (
|
|
<p
|
|
role="alert"
|
|
className="px-4 py-2 flex gap-2 items-center bg-red-500 text-white rounded-sm shadow-md"
|
|
>
|
|
<span className="flex-grow">{children}</span>
|
|
{onClose
|
|
? (
|
|
<button
|
|
type="button"
|
|
className="button-ghost"
|
|
onClick={() => onClose()}
|
|
>
|
|
Close
|
|
</button>
|
|
)
|
|
: null}
|
|
</p>
|
|
);
|
|
}
|