Files
cobble/src/pages/admin/settings/(partials)/envs/scoped-envs-group.tsx
T
tben 96735de48f Let a bot and a workspace set their own envs
Envs had three scopes, general, workspace and computer. A bot had no
scope of its own, so the only way to give one worker a key was to set it
on a computer it happened to share.

The envs table gets a bot_id, and resolution now layers bot over
computer over workspace over general, so a bot's own key wins wherever it
runs. Every computer call site passes the run's bot_id, and grabRunEnvs
does the same for the {{env.KEY}} a custom tool or an MCP server's headers
read.

A bot's and a workspace's settings page can now edit their own envs, in
place, through the same save-env and delete-env routes: sending `scoped`
makes them answer with just that scope instead of the whole install's
overview. Super admins only, like the Environment page.
2026-10-22 08:30:40 +01:00

43 lines
1.2 KiB
TypeScript

import { useState } from "react";
import type { EnvsMutationResult, ScopedEnvsPayload } from "@/src/types";
import EnvsGroup from "./envs-group";
type Props = {
/**
* A bot's own envs, or a workspace's. `null` when the viewer can't
* manage them, so the group isn't rendered at all.
*/
initial?: ScopedEnvsPayload | null;
};
/**
* The envs set on one bot or one workspace, on its settings page. Super
* admins only, like the Environment page.
*/
export default function ScopedEnvsGroup({ initial }: Props) {
const [data, setData] = useState<ScopedEnvsPayload | null>(initial || null);
const [status, setStatus] = useState<{
error?: boolean;
success?: boolean;
msg?: string;
}>();
if (!data?.can_manage) return null;
const changed = (result: EnvsMutationResult, msg: string) => {
if (result.scoped) setData(result.scoped);
setStatus({ success: true, msg });
};
return (
<EnvsGroup
scope={data.scope}
envs={data.envs}
scoped
status={status}
onChanged={changed}
onError={(msg) => setStatus({ error: true, msg })}
/>
);
}