Files
fusion/packages/dashboard/app/components/settings/sections/NodeRoutingSection.tsx
gsxdsm 4baa4c43c5 FN-7505: show defaults in settings descriptions
Expose settings defaults directly in dashboard help text so operators can see baseline values while editing settings.

- Add default-value wording across global and project settings descriptions and locale strings.
- Document the dashboard/default-reference alignment and add a changeset for the published CLI package.
- Add coverage that every visible settings field includes its default in helper text and update existing assertions.

Files changed:
 .changeset/fn-7505-settings-default-descriptions.md       |   7 +
 docs/dashboard-guide.md                                    |   3 +
 docs/settings-reference.md                                 |   3 +
 .../__tests__/SettingsModal.general.test.tsx               |   2 +-
 .../settings/sections/AgentPermissionsSection.tsx          |   4 +-
 .../settings/sections/AppearanceSection.tsx                |   4 +-
 .../settings/sections/BackupsSection.tsx                   |  13 +-
 .../settings/sections/CommandsSection.tsx                  |   4 +-
 .../settings/sections/ExperimentalSection.tsx              |   2 +-
 .../settings/sections/GeneralSection.tsx                   |  26 +-
 .../settings/sections/GlobalGeneralSection.tsx             |  25 +-
 .../settings/sections/GlobalModelsSection.tsx              |  24 +-
 .../settings/sections/McpServersCard.tsx                   |   1 +
 .../components/settings/sections/MemorySection.tsx         |  12 +-
 .../components/settings/sections/MergeSection.tsx          |  37 +-
 .../settings/sections/ModelPricingSection.tsx              |   2 +-
 .../settings/sections/NodeRoutingSection.tsx               |   3 +-
 .../settings/sections/NodeSyncSection.tsx                  |   6 +-
 .../settings/sections/NotificationsSection.tsx             |  14 +-
 .../settings/sections/ProjectModelsSection.tsx             |  11 +-
 .../settings/sections/PromptsSection.tsx                   |   2 +-
 .../components/settings/sections/RemoteSection.tsx         |   7 +-
 .../settings/sections/ResearchGlobalSection.tsx            |  15 +-
 .../settings/sections/ResearchProjectSection.tsx           |  16 +-
 .../settings/sections/ScheduledEvalsSection.tsx            |   7 +-
 .../settings/sections/SchedulingSection.tsx                |  20 +-
 .../settings/sections/WorktreesSection.tsx                 |  14 +-
 .../sections/__tests__/AppearanceSection.test.tsx          |   4 +-
 .../MergeSection.legacy-automerge-cleanup.test.tsx         |   2 +-
 .../settings-default-descriptions.test.tsx                 | 573 +++++++++++++++++++++
 packages/i18n/locales/en/app.json                          | 261 ++++++----
 31 files changed, 914 insertions(+), 210 deletions(-)

Fusion-Task-Id: FN-7505

Fusion-Task-Lineage: 7688caf2-2a95-4401-8b27-9da4b46ecfcd

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 13:09:29 -07:00

64 lines
3.7 KiB
TypeScript

import type { ReactNode } from "react";
import type { NodeInfo } from "../../../api";
import { NodeHealthDot } from "../../NodeHealthDot";
import type { SettingsFormState, SetSettingsForm } from "./context";
import { useTranslation } from "react-i18next";
function getNodeStatusLabel(status: "online" | "offline" | "connecting" | "error", t: ReturnType<typeof useTranslation<"app">>["t"]): string {
if (status === "online")
return t("settings.nodeRouting.statusOnline", "Online");
if (status === "connecting")
return t("settings.nodeRouting.statusConnecting", "Connecting");
if (status === "error")
return t("settings.nodeRouting.statusError", "Error");
return t("settings.nodeRouting.statusOffline", "Offline");
}
export interface NodeRoutingSectionProps {
scopeBanner: ReactNode;
form: SettingsFormState;
setForm: SetSettingsForm;
nodes: NodeInfo[];
}
export function NodeRoutingSection({ scopeBanner, form, setForm, nodes }: NodeRoutingSectionProps) {
const { t } = useTranslation("app");
return (<>
{scopeBanner}
<h4 className="settings-section-heading">{t("settings.nodeRouting.nodeRouting", "Node Routing")}</h4>
<p className="settings-section-description">{t("settings.nodeRouting.configureHowTasksAreRoutedToExecutionNodes", "Configure how tasks are routed to execution nodes.")}</p>
<p className="settings-node-routing-note">{t("settings.nodeRouting.theseSettingsApplyAtTheProjectLevel", "These settings apply at the project level.")}</p>
<div className="form-group">
<label htmlFor="defaultNodeId">{t("settings.nodeRouting.defaultExecutionNode", "Default Execution Node")}</label>
<select id="defaultNodeId" className="select" value={typeof form.defaultNodeId === "string" ? form.defaultNodeId : ""} onChange={(e) => {
const val = e.target.value;
setForm((f) => ({ ...f, defaultNodeId: val || undefined } as SettingsFormState));
}}>
<option value="">{t("settings.nodeRouting.localExecutionNoDefaultNode", "Local execution (no default node)")}</option>
{nodes.map((node) => (<option key={node.id} value={node.id}>
{node.name} ({getNodeStatusLabel(node.status, t)})
</option>))}
</select>
{(() => {
const selectedNode = nodes.find((node) => node.id === form.defaultNodeId);
if (!selectedNode)
return null;
return (<div className="settings-node-status">
<span>{t("settings.nodeRouting.selectedNode", "Selected node:")}</span>
<NodeHealthDot status={selectedNode.status} showLabel/>
</div>);
})()}
<small>{t("settings.nodeRouting.usedWhenATaskHasNoNodeOverride", "Used when a task has no node override. Node status is shown for safer routing selection. No default \u2014 unset (local execution).")}</small>
</div>
<div className="form-group">
<label htmlFor="unavailableNodePolicy">{t("settings.nodeRouting.unavailableNodePolicy", "Unavailable Node Policy")}</label>
<select id="unavailableNodePolicy" className="select" value={form.unavailableNodePolicy === "fallback-local" ? "fallback-local" : "block"} onChange={(e) => setForm((f) => ({
...f,
unavailableNodePolicy: e.target.value as "block" | "fallback-local",
} as SettingsFormState))}>
<option value="block">{t("settings.nodeRouting.blockExecution", "Block execution")}</option>
<option value="fallback-local">{t("settings.nodeRouting.fallBackToLocal", "Fall back to local")}</option>
</select>
<small>{t("settings.nodeRouting.unavailableNodePolicyHint", "Default: block execution.")}</small>
</div>
</>);
}
export default NodeRoutingSection;