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>
64 lines
3.7 KiB
TypeScript
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;
|