- 51 fix agents covered every dirty batch from the round-1 verifiers: helper-function labels (roles, statuses, relative time), constant label maps (SETTINGS_SECTIONS, PROVIDER_INFO, EVENT_TYPE_LABELS), TUI help overlay + tab labels, toasts, placeholders, aria-labels - Inline markup flattened by round 1 restored with <Trans> (DbCorruptionBanner storage-docs link, UpdateAvailableBanner code chip) - Catalogs merged: +527 en keys across 5 locales; CLI bundles + app locale tree regenerated (6 locales) - All 23 sweep-caused test regressions fixed: delta vs the clean-main baseline is now zero (remaining 4 local failures reproduce identically on origin/main; CI-green upstream) - typecheck/lint clean; TUI 82/82, core locale 9/9 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import { useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { NodeInfo } from "../api";
|
|
import "./ProjectNodeSelector.css";
|
|
|
|
interface ProjectNodeSelectorProps {
|
|
projectId: string;
|
|
currentNodeId?: string;
|
|
onSelect: (nodeId: string | null) => void;
|
|
nodes: NodeInfo[];
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export function ProjectNodeSelector({
|
|
projectId,
|
|
currentNodeId,
|
|
onSelect,
|
|
nodes,
|
|
disabled = false,
|
|
}: ProjectNodeSelectorProps) {
|
|
const { t } = useTranslation("app");
|
|
const sortedNodes = useMemo(() => {
|
|
return [...nodes].sort((a, b) => a.name.localeCompare(b.name));
|
|
}, [nodes]);
|
|
|
|
const selectedValue = currentNodeId ?? "";
|
|
|
|
return (
|
|
<label className="project-node-selector" htmlFor={`project-node-selector-${projectId}`}>
|
|
<span className="project-node-selector__label">{t("nodes.runtimeNodeLabel", "Runtime Node")}</span>
|
|
<select
|
|
className="select"
|
|
id={`project-node-selector-${projectId}`}
|
|
value={selectedValue}
|
|
onChange={(event) => {
|
|
const value = event.target.value;
|
|
onSelect(value ? value : null);
|
|
}}
|
|
disabled={disabled}
|
|
>
|
|
<option value="">{t("nodes.autoAssignment", "Auto (no assignment)")}</option>
|
|
{sortedNodes.map((node) => (
|
|
<option
|
|
key={node.id}
|
|
value={node.id}
|
|
title={t("nodes.statusTitle", "Status: {{status}}", { status: node.status })}
|
|
className={node.status === "offline" || node.status === "error" ? "project-node-selector__option--dim" : ""}
|
|
>
|
|
{t("nodes.nodeLabel", "{{name}} ({{type}}) — {{status}}", { name: node.name, type: node.type, status: node.status })}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
);
|
|
}
|