8000 feat(settings): fold the options most people leave as they are by adeelahmad · Pull Request #392 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ci/clicks/survey.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ async function surveyPages(page, base, phone) {
page.evaluate(() => {
const main = document.querySelector("main") || document.body;
const seen = [...main.querySelectorAll("a[href], button, input, select, textarea, [role=tab], [role=switch], [role=radio]")];
// the page's own controls: not the settings sections or tabs that lead to other pages
return seen.filter((el) => el.offsetParent !== null && !el.closest("[hidden], nav")).length;
// the page's own controls: not the settings sections or tabs that lead to other pages, nor what a closed fold
// (details) keeps out of sight, which Chromium still lays out
return seen.filter((el) => el.offsetParent !== null && !el.closest("[hidden], nav, details:not([open]) > :not(summary)")).length;
});
const settle = () => page.waitForTimeout(1200);
await page.goto(base + "/", { waitUntil: "domcontentloaded" });
Expand Down
8 changes: 5 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,11 @@ The sections are in groups: AI and search, Speech and voices, Media and document
access, Files and devices, and System. **Find a setting** at the top of the list (or `/`) finds a section by its name
or what it's for, and a single setting by its label, hint or choices: Enter opens the first, and a setting found by
its label opens with its field in focus and its value selected, so typing replaces it. ⌘K (Ctrl+K) finds settings
the same way, beside recordings and pages. Agents reach the same settings through the API
(`GET/PUT /api/v1/settings/<section>`), and the admin assistant through `read_settings` and `change_settings`
([Assistant](assistant.md#setting-up-and-running-the-server-by-chat)).
the same way, beside recordings and pages. In a section, the options most people leave as they are (tuning numbers,
file types, the assistant's tool list, a provider not yet set up) are folded under a line that names them; a fold
opens by itself when one of its fields has an error, and Find opens it on the field it found. Agents reach the same
settings through the API (`GET/PUT /api/v1/settings/<section>`), and the admin assistant through `read_settings` and
`change_settings` ([Assistant](assistant.md#setting-up-and-running-the-server-by-chat)).

## Word search

Expand Down
5 changes: 5 additions & 0 deletions nextjs-frontend/__tests__/settings-admin-models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jest.mock("next-auth/react", () => ({
const spec = (id: string) => FIELDS.find((f) => fieldId(f) === id)!;

describe("settings fields", () => {
it("reads back an unset Laya server as unset, so the AI assistant doesn't open with a change", () => {
const f = spec("decisions.laya_url");
expect(parse(f, toUi(f, null))).toEqual({ value: null });
});

it("shows and parses values like the backend stores them", () => {
expect(toUi(spec("server.session_hours"), 168)).toBe("7");
expect(parse(spec("server.session_hours"), "7")).toEqual({ value: 168 });
Expand Down
36 changes: 36 additions & 0 deletions nextjs-frontend/__tests__/settings-save.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,39 @@ describe("opened on one setting", () => {
expect(port.closest("[data-setting]")).toHaveClass("setting-found");
});
});

describe("options most people leave alone", () => {
const UPLOADS = {
uploads: { values: { max_mb: 2048, chunk_mb: 8, expire_hours: 24, extensions: [".mp3", ".wav"] } },
} as unknown as SettingsView;
const uploads = (field?: string) =>
render(
<QueryClientProvider client={new QueryClient()}>
<TooltipProvider>
<SettingsSection id="uploads" view={UPLOADS} => undefined} field={field} />
</TooltipProvider>
</QueryClientProvider>,
);

it("are folded under a line saying what's in them, the main one left in view", () => {
uploads();
expect(screen.getByLabelText("Largest audio or video file (MB)").closest("details")).toBeNull();
const fold = screen.getByLabelText("Piece size (MB)").closest("details")!;
expect(fold).not.toHaveAttribute("open");
expect(fold.querySelector("summary")).toHaveTextContent("File types (2 of 20)");
});

it("open by themselves when one has an error", () => {
uploads();
const piece = screen.getByLabelText("Piece size (MB)");
fireEvent.change(piece, { target: { value: "0" } });
expect(piece.closest("details")).toHaveAttribute("open");
});

it("open on the field Find or ⌘K found", async () => {
uploads("uploads.expire_hours");
const hours = screen.getByLabelText("Keep unfinished uploads for (hours)");
expect(hours.closest("details")).toHaveAttribute("open");
await waitFor(() => expect(hours).toHaveFocus());
});
});
2 changes: 1 addition & 1 deletion nextjs-frontend/components/import/upload-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ export function ProblemCard({
)}
{mediaType && admin && (
<Button asChild size="sm" variant="ghost">
<Link href="/settings/uploads">Upload settings</Link>
<Link href="/settings/uploads?field=uploads.extensions">Upload settings</Link>
</Button>
)}
{onKind && it.kind === "transcript" && canBeTranscript(it.file.name) && (
Expand Down
2 changes: 1 addition & 1 deletion nextjs-frontend/components/podcasts/episode-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export function EpisodePage({ id }: { id: number }) {
{ep.status === "script_only" && (
<Banner tone="warning" title="No voices yet.">
Text to speech isn’t set up, so there’s a script but no audio.{" "}
<Link href="/settings/ai" className="font-semibold text-fg-accent hover:underline">
<Link href="/settings/ai?field=voice.tts_provider" className="font-semibold text-fg-accent hover:underline">
Set it up in Settings
</Link>
, then remake it.
Expand Down
Loading
Loading
0