Add bot schedules (routines), open Activity, add Help and a Desktop computer view

Bots create, list, update and delete schedules (cron_jobs, Bun.cron in UTC);
a per-minute cron queues due runs as tasks. Routines, Activity (super admins)
and Help get their own rail aside. Help covers familiar problems, starting
with signing in to Google through Cookie-Editor over the new Desktop (noVNC)
view.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-19 10:52:32 +01:00
co-authored by Claude Opus 5.5
parent f24c0d7e82
commit c44048dbab
62 changed files with 1904 additions and 78 deletions
@@ -7,15 +7,19 @@ type Props = {
title: string;
description?: ReactNode;
children: ReactNode;
/**
* An anchor, so a link can open the page at this block.
*/
id?: string;
};
/**
* One block of settings: what it is on the left, the controls on the right.
* Stacks below 768px. Blocks are separated by hairlines, never cards.
*/
export default function SettingsGroup({ title, description, children }: Props) {
export default function SettingsGroup({ title, description, children, id }: Props) {
return (
<Stack className="w-full gap-4! md:grid md:grid-cols-[200px_1fr] md:gap-10! py-8 border-0 border-b border-solid border-hairline last:border-b-0">
<Stack id={id} className="w-full scroll-mt-4 gap-4! md:grid md:grid-cols-[200px_1fr] md:gap-10! py-8 border-0 border-b border-solid border-hairline last:border-b-0">
<Stack className="gap-1! min-w-0">
<H2 className="text-sm! leading-5! tracking-normal! font-bold text-ink mb-0!">
{title}
@@ -1,4 +1,5 @@
import type { ReactNode } from "react";
import { twMerge } from "tailwind-merge";
import Stack from "@moduletrace/twui/layout/Stack";
import SettingsPaneHeader from "./settings-pane-header";
@@ -6,18 +7,32 @@ type Props = {
title: string;
description: string;
children: ReactNode;
/**
* A wider column, for tables (activity).
*/
wide?: boolean;
};
/**
* The settings pane beside the rail: a 64px header like the conversation
* header, then one readable column that scrolls on its own.
*/
export default function SettingsShell({ title, description, children }: Props) {
export default function SettingsShell({
title,
description,
children,
wide,
}: Props) {
return (
<Stack className="grow min-w-0 h-full gap-0! items-stretch">
<SettingsPaneHeader title={title} description={description} />
<Stack className="grow min-h-0 overflow-y-auto gap-0! items-stretch">
<Stack className="w-full max-w-[760px] mx-auto gap-0! items-stretch px-6 lg:px-10 pb-16">
<Stack
className={twMerge(
"w-full max-w-container mx-auto gap-0! items-stretch px-6 lg:px-10 pb-16",
wide && "max-w-[1200px]",
)}
>
{children}
</Stack>
</Stack>