Pad env rows and reflow the envs group
CI / check (push) Canceled after 0s

Give each env row its own horizontal padding so the key lines up with the
group's other content, and reflow the props and description literals in
env-row and envs-group.
This commit is contained in:
2026-10-22 15:24:58 +01:00
parent e1faa2141e
commit 89e57cc467
2 changed files with 55 additions and 12 deletions
@@ -2,10 +2,16 @@ import { useState } from "react";
import Row from "@moduletrace/twui/layout/Row";
import Span from "@moduletrace/twui/layout/Span";
import Stack from "@moduletrace/twui/layout/Stack";
import type { EnvScope, EnvsMutationResult, KnownEnvStatus, PublicEnv } from "@/src/types";
import type {
EnvScope,
EnvsMutationResult,
KnownEnvStatus,
PublicEnv,
} from "@/src/types";
import postEnvApi from "../../(functions)/post-env-api";
import EnvForm from "./env-form";
import EnvRowActions from "./env-row-actions";
import { twMerge } from "tailwind-merge";
type Props = {
scope: EnvScope;
@@ -27,14 +33,26 @@ type Props = {
* One env: its key, description and value (or "secret"), with Edit and
* Remove. Edit opens the form in place.
*/
export default function EnvRow({ scope, env, known, scoped, onChanged, onError }: Props) {
export default function EnvRow({
scope,
env,
known,
scoped,
onChanged,
onError,
}: Props) {
const [editing, setEditing] = useState(false);
const [busy, setBusy] = useState(false);
const key = env?.key || known?.key || "";
const remove = async () => {
if (!env || busy) return;
if (!window.confirm(`Remove ${key}? Computers drop it on their next run.`)) return;
if (
!window.confirm(
`Remove ${key}? Computers drop it on their next run.`,
)
)
return;
setBusy(true);
const res = await postEnvApi({
@@ -43,7 +61,8 @@ export default function EnvRow({ scope, env, known, scoped, onChanged, onError }
});
setBusy(false);
if (res.success && res.singleRes) onChanged(res.singleRes, res.msg || "Removed.");
if (res.success && res.singleRes)
onChanged(res.singleRes, res.msg || "Removed.");
else onError(res.msg || "Couldn't remove the env.");
};
@@ -72,12 +91,22 @@ export default function EnvRow({ scope, env, known, scoped, onChanged, onError }
? "From the server's environment"
: "Not set";
const flags = env && !env.known && !env.expose_to_computers ? " · not on computers" : "";
const flags =
env && !env.known && !env.expose_to_computers
? " · not on computers"
: "";
return (
<Row className="w-full gap-3! flex-nowrap items-start justify-between py-3 border-0 border-b border-solid border-hairline last:border-b-0">
<Row
className={twMerge(
"w-full gap-3! flex-nowrap items-start justify-between py-3 px-4",
"border-0 border-b border-solid border-hairline last:border-b-0",
)}
>
<Stack className="gap-0.5! min-w-0">
<Span className="text-sm font-bold leading-5 text-ink truncate">{key}</Span>
<Span className="text-sm font-bold leading-5 text-ink truncate">
{key}
</Span>
{env?.description || known?.description ? (
<Span className="text-[13px] leading-[18px] text-ink-secondary break-words">
{known?.description || env?.description}
@@ -34,20 +34,34 @@ type Props = {
};
const Descriptions: Record<EnvScope["paradigm"], string> = {
general: "Set everywhere. A workspace, a bot or a computer can set the same key to override it.",
workspace: "For every bot working here. Beats general, loses to the bot's own.",
computer: "For this computer only. Beats a workspace, loses to the bot's own.",
general:
"Set everywhere. A workspace, a bot or a computer can set the same key to override it.",
workspace:
"For every bot working here. Beats general, loses to the bot's own.",
computer:
"For this computer only. Beats a workspace, loses to the bot's own.",
bot: "For this bot only, everywhere it works. Beats the workspace, the computer and general.",
};
/**
* The envs bots and computers use, in one scope, with an add form.
*/
export default function EnvsGroup({ scope, envs, scoped, title, status, onChanged, onError }: Props) {
export default function EnvsGroup({
scope,
envs,
scoped,
title,
status,
onChanged,
onError,
}: Props) {
const [adding, setAdding] = useState(false);
return (
<SettingsGroup title={title || "Envs"} description={Descriptions[scope.paradigm]}>
<SettingsGroup
title={title || "Envs"}
description={Descriptions[scope.paradigm]}
>
<SettingsList is_empty={!envs.length} empty="Nothing set here yet.">
{envs.map((env) => (
<EnvRow