316 lines
9.8 KiB
TypeScript
316 lines
9.8 KiB
TypeScript
import React, { useState } from "react";
|
|
import useSWR from "swr";
|
|
import { cx } from "twind/core";
|
|
import { fetchApi, handleResponse } from "./apiClient.ts";
|
|
|
|
export function SettingsPage(props: { sessionId: string | null }) {
|
|
const { sessionId } = props;
|
|
|
|
const getSession = useSWR(
|
|
sessionId ? ["sessions/{sessionId}", "GET", { params: { sessionId } }] as const : null,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const getUser = useSWR(
|
|
getSession.data?.userId
|
|
? ["users/{userId}", "GET", { params: { userId: String(getSession.data.userId) } }] as const
|
|
: null,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const getParams = useSWR(
|
|
["settings/params", "GET", {}] as const,
|
|
(args) => fetchApi(...args).then(handleResponse),
|
|
);
|
|
const [newParams, setNewParams] = useState<Partial<typeof getParams.data>>({});
|
|
const [patchParamsError, setPatchParamsError] = useState<string>();
|
|
|
|
return (
|
|
<form
|
|
className="flex flex-col items-stretch gap-4"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
getParams.mutate(() =>
|
|
fetchApi("settings/params", "PATCH", {
|
|
query: { sessionId: sessionId ?? "" },
|
|
body: { type: "application/json", data: newParams ?? {} },
|
|
}).then(handleResponse)
|
|
)
|
|
.then(() => setNewParams({}))
|
|
.catch((e) => setPatchParamsError(String(e)));
|
|
}}
|
|
>
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Negative prompt {newParams?.negative_prompt != null ? "(Changed)" : ""}
|
|
</span>
|
|
<textarea
|
|
className="input-text"
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.negative_prompt ??
|
|
getParams.data?.negative_prompt ??
|
|
""}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
negative_prompt: e.target.value,
|
|
}))}
|
|
/>
|
|
</label>
|
|
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Sampler {newParams?.sampler_name != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.sampler_name ??
|
|
getParams.data?.sampler_name ??
|
|
""}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
sampler_name: e.target.value,
|
|
}))}
|
|
/>
|
|
</label>
|
|
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Steps {newParams?.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={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.steps ??
|
|
getParams.data?.steps ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
steps: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range flex-grow"
|
|
type="range"
|
|
min={5}
|
|
max={50}
|
|
step={5}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.steps ??
|
|
getParams.data?.steps ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
steps: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</span>
|
|
</label>
|
|
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Detail {newParams?.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={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.cfg_scale ??
|
|
getParams.data?.cfg_scale ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
cfg_scale: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range flex-grow"
|
|
type="range"
|
|
min={1}
|
|
max={20}
|
|
step={1}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.cfg_scale ??
|
|
getParams.data?.cfg_scale ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((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 {newParams?.width != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
type="number"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.width ??
|
|
getParams.data?.width ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
width: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range"
|
|
type="range"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.width ??
|
|
getParams.data?.width ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
width: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</label>
|
|
<label className="flex flex-1 flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Height {newParams?.height != null ? "(Changed)" : ""}
|
|
</span>
|
|
<input
|
|
className="input-text"
|
|
type="number"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.height ??
|
|
getParams.data?.height ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
height: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range"
|
|
type="range"
|
|
min={64}
|
|
max={2048}
|
|
step={64}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.height ??
|
|
getParams.data?.height ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
height: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</label>
|
|
</div>
|
|
|
|
<label className="flex flex-col items-stretch gap-1">
|
|
<span className="text-sm">
|
|
Daily limit {newParams?.maxDailyJobs != null ? "(Changed)" : ""}
|
|
</span>
|
|
<span className="flex items-center gap-1">
|
|
<input
|
|
className="input-text w-20"
|
|
type="number"
|
|
min={1}
|
|
max={500}
|
|
step={1}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.maxDailyJobs ??
|
|
getParams.data?.maxDailyJobs ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
dailyLimit: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
<input
|
|
className="input-range flex-grow"
|
|
type="range"
|
|
min={1}
|
|
max={500}
|
|
step={1}
|
|
disabled={getParams.isLoading || !getUser.data?.admin}
|
|
value={newParams?.maxDailyJobs ??
|
|
getParams.data?.maxDailyJobs ??
|
|
0}
|
|
onChange={(e) =>
|
|
setNewParams((params) => ({
|
|
...params,
|
|
maxDailyJobs: Number(e.target.value),
|
|
}))}
|
|
/>
|
|
</span>
|
|
</label>
|
|
|
|
{patchParamsError
|
|
? (
|
|
<p className="alert">
|
|
<span className="flex-grow">Updating params failed: {patchParamsError}</span>
|
|
<button className="button-ghost" onClick={() => setPatchParamsError(undefined)}>
|
|
Close
|
|
</button>
|
|
</p>
|
|
)
|
|
: null}
|
|
{getParams.error
|
|
? (
|
|
<p className="alert">
|
|
<span className="flex-grow">
|
|
Loading params failed: {String(getParams.error)}
|
|
</span>
|
|
</p>
|
|
)
|
|
: null}
|
|
|
|
<div className="flex gap-2 items-center justify-end">
|
|
<button
|
|
type="button"
|
|
className={cx("button-outlined ripple", getParams.isLoading && "bg-stripes")}
|
|
disabled={getParams.isLoading || !getUser.data?.admin ||
|
|
Object.keys(newParams ?? {}).length === 0}
|
|
onClick={() => setNewParams({})}
|
|
>
|
|
Reset
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className={cx("button-filled ripple", getParams.isLoading && "bg-stripes")}
|
|
disabled={getParams.isLoading || !getUser.data?.admin ||
|
|
Object.keys(newParams ?? {}).length === 0}
|
|
>
|
|
Save
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|