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
2 changes: 1 addition & 1 deletion config-editor-ui/src/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ICONS = {
export const SECTION_ICONS = {
"get-running": "flag", environment: "terminal",
core: "flag", auth: "lock", cache_store: "gauge",
observability: "activity", runs: "play", websocket: "bolt", ag_ui: "external", remote_tools: "wrench",
observability: "activity", metrics: "gauge", runs: "play", websocket: "bolt", ag_ui: "external", remote_tools: "wrench",
media: "file", checkpointer: "layers", id_generator: "key", thread_name_generator: "file", store: "box",
injectq: "arrows", test: "flask", evaluation: "target",
};
29 changes: 9 additions & 20 deletions config-editor-ui/src/pages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { Field, fieldGroups } from "./fields.jsx";
import { SECTION_ICONS } from "./icons.js";
import {
PAGES, WIDGET_FIELD_IDS, isAgentReady, isObject, isOn, issuesFor, navItem, section, store,
valueOrDefault,
} from "./store.js";
import { Callout, Icon, IssueCallout, Segmented } from "./ui.jsx";
import { Callout, Disclosure, Icon, IssueCallout, Segmented } from "./ui.jsx";
import {
AuthWidget, CacheStoreWidget, ChoiceWidget, RemoteToolsWidget,
} from "./widgets.jsx";
import { MetricsWidget, TracingWidget, metricsSummary, traceSummary } from "./telemetry.jsx";

const Heading = ({ children, code }) => (
<h1 id="page-title" tabindex={-1} class="flex flex-wrap items-baseline gap-x-3 gap-y-1 text-2xl font-semibold tracking-tight text-ink focus:outline-none">
Expand Down Expand Up @@ -68,21 +68,11 @@ function cacheSummary() {
return { text: `${parts.join("; ")}.` };
}

function traceSummary() {
const o = store.config.observability;
if (o === undefined || o === null) return { text: offText("observability") };
const on = [];
if (valueOrDefault(["observability", "logfire", "enabled"])) on.push("Logfire");
if (valueOrDefault(["observability", "langsmith", "enabled"])) on.push("LangSmith");
const level = valueOrDefault(["observability", "level"]);
return { text: `Level ${level}${on.length ? `, sending to ${on.join(" and ")}` : ", no destination chosen yet"}.` };
}

function GetRunning() {
const core = section("core");
const ready = isAgentReady();
const general = core ? issuesFor("core").filter((i) => !core.fields.some((f) => f.path.join(".") === i.path)) : [];
const rows = [["auth", authSummary()], ["cache_store", cacheSummary()], ["observability", traceSummary()]];
const rows = [["auth", authSummary()], ["cache_store", cacheSummary()], ["observability", traceSummary(offText)], ["metrics", metricsSummary(offText)]];
const all = store.nav.flatMap((g) => g.items).filter((id) => id !== "get-running");
return (
<>
Expand Down Expand Up @@ -140,19 +130,18 @@ export function EnvList({ vars }) {
function EnvDisclosure({ vars, open }) {
if (!vars?.length) return null;
return (
<details class="group mt-9 border-t border-line pt-1" open={open}>
<summary class="focus-ring flex min-h-11 cursor-pointer list-none items-center gap-2 font-medium text-muted [&::-webkit-details-marker]:hidden">
<Icon name="chevronRight" class="size-4 transition-transform group-open:rotate-90" />Set in .env
</summary>
<Disclosure title="Set in .env" open={open} class="mt-9 border-t border-line pt-1">
<p class="mb-2 text-xs text-faint">Read only. The editor never reads .env, so only names are shown.</p>
<EnvList vars={vars} />
</details>
</Disclosure>
);
}

function SectionWidget({ sec }) {
if (sec.widget === "auth") return <AuthWidget sec={sec} />;
if (sec.widget === "remote_tools") return <RemoteToolsWidget />;
if (sec.widget === "observability") return <TracingWidget />;
if (sec.widget === "metrics") return <MetricsWidget />;
if (sec.widget === "cache_store") return <CacheStoreWidget sec={sec} />;
if (sec.widget === "id_generator" || sec.widget === "thread_name_generator") return <ChoiceWidget sec={sec} />;
return null;
Expand All @@ -172,7 +161,7 @@ export function generalIssues(sec) {
// Fields and widget of a section, no heading. Shared by the page and search results.
export function SectionFields({ sec }) {
const on = isOn(sec);
const widget = sec.widget && (on || !sec.optional);
const widget = sec.widget && (on || !sec.optional || sec.self_managed);
return (
<>
{widget ? <div class="mt-6"><SectionWidget sec={sec} /></div> : null}
Expand All @@ -198,7 +187,7 @@ function SectionPage({ sec }) {
<Heading code={sec.key}>{sec.title}</Heading>
<Lead>{sec.description}</Lead>
{general.length ? <div class="mt-4 space-y-2">{general.map((i, n) => <IssueCallout key={n} issue={i} />)}</div> : null}
{sec.optional ? (
{sec.optional && !sec.self_managed ? (
<div class="mt-5 flex flex-wrap items-center gap-4">
<Segmented
label={`Settings for ${sec.title}`} value={on ? "c" : "d"}
Expand Down
2 changes: 1 addition & 1 deletion config-editor-ui/src/sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function Markers({ id }) {
if (!changed && !issue) return null;
return (
<span class="flex shrink-0 gap-1">
{changed ? <span class="size-2 rounded-full bg-brand" title="Changed from default" /> : null}
{changed ? <span class="size-2 rounded-full bg-brand" title={section(id).self_managed ? "Configured" : "Changed from default"} /> : null}
{issue ? (
<span
class={`size-2 rounded-full ${issue.level === "error" ? "bg-danger" : "bg-warn"}`}
Expand Down
3 changes: 2 additions & 1 deletion config-editor-ui/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// are pages of their own rather than schema sections.
export const NAV = [
{ label: null, items: ["get-running"] },
{ label: "Before production", items: ["auth", "cache_store", "observability"] },
{ label: "Before production", items: ["auth", "cache_store", "observability", "metrics"] },
{ label: "Runs and streaming", items: ["runs", "websocket", "ag_ui", "remote_tools", "media"] },
{ label: "Project wiring", items: ["checkpointer", "id_generator", "thread_name_generator", "store", "injectq"] },
{ label: "Developer tools", items: ["test", "evaluation"] },
Expand Down Expand Up @@ -155,6 +155,7 @@ export const fieldChanged = (f) => {
export const sectionChanged = (sec) => {
if (sec.id === "core") return false;
if (sec.id === "auth") return store.config.auth != null;
if (sec.id === "metrics") return store.config.metrics?.enabled === true;
return sec.optional ? isOn(sec) : sec.fields.some(fieldChanged);
};
// Highest-severity issue of a section, or null.
Expand Down
Loading
Loading