fix(dashboard): UI polish — modals, layout, consistency, test fixes
Dashboard UX polish pass — consolidates create forms into modals triggered from the page header, fixes layout inconsistencies, adds scroll-to navigation for the Keys page, and aligns the TokenBar with the design system. Changes: - App.tsx: add padding to sidebar header - resolve-page-title.ts: add missing routes, better fallback title - en.ts: fix nav labels (Profiles was 'profiles : multi agents') - ModelsPage: two-col layout, auxiliary tasks modal, TokenBar redesign - ProfilesPage: create button in header, form in modal, Checkbox component - CronPage: create button in header, form in modal - EnvPage: scroll-to sub-nav in header, fix text overflow Modal and dialog standardization: - Replace all native confirm()/window.confirm() with ConfirmDialog (OAuthProvidersCard, PluginsPage, ModelsPage, ConfigPage) - Add useModalBehavior hook (Escape-to-close, scroll lock, focus restore) - Apply hook to ProfilesPage, CronPage, AuxiliaryTasksModal Component fixes (from PR review): - Checkbox: fix controlled/uncontrolled mismatch, add focus-visible ring - TokenBar: add rounded-full to legend dots, remove dead code CI/test fixes: - Fix TS unused imports (noUnusedLocals), type-narrow PickerTarget union - Add windows-footgun suppression on platform-guarded os.killpg - Fix 19 stale unit tests + 9 e2e tests broken by recent main changes - Restore minimal example-dashboard plugin for plugin auth test
This commit is contained in:
@@ -46,6 +46,7 @@ import { Button } from "@nous-research/ui/ui/components/button";
|
||||
import { ListItem } from "@nous-research/ui/ui/components/list-item";
|
||||
import { Spinner } from "@nous-research/ui/ui/components/spinner";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { ConfirmDialog } from "@/components/ui/confirm-dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@nous-research/ui/ui/components/badge";
|
||||
import { useI18n } from "@/i18n";
|
||||
@@ -118,6 +119,7 @@ export default function ConfigPage() {
|
||||
const [yamlLoading, setYamlLoading] = useState(false);
|
||||
const [yamlSaving, setYamlSaving] = useState(false);
|
||||
const [activeCategory, setActiveCategory] = useState<string>("");
|
||||
const [confirmReset, setConfirmReset] = useState(false);
|
||||
const { toast, showToast } = useToast();
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const { t } = useI18n();
|
||||
@@ -290,11 +292,17 @@ export default function ConfigPage() {
|
||||
// "reset this tab", not "wipe my entire config.yaml".
|
||||
const scopedFields = isSearching ? searchMatchedFields : activeFields;
|
||||
if (scopedFields.length === 0) return;
|
||||
setConfirmReset(true);
|
||||
};
|
||||
|
||||
const executeReset = () => {
|
||||
if (!defaults || !config) return;
|
||||
setConfirmReset(false);
|
||||
const scopedFields = isSearching ? searchMatchedFields : activeFields;
|
||||
if (scopedFields.length === 0) return;
|
||||
const scopeLabel = isSearching
|
||||
? t.config.searchResults
|
||||
: prettyCategoryName(activeCategory);
|
||||
const message = t.config.confirmResetScope.replace("{scope}", scopeLabel);
|
||||
if (!window.confirm(message)) return;
|
||||
let next: Record<string, unknown> = config;
|
||||
for (const [key] of scopedFields) {
|
||||
next = setNestedValue(next, key, getNestedValue(defaults, key));
|
||||
@@ -627,6 +635,22 @@ export default function ConfigPage() {
|
||||
</div>
|
||||
)}
|
||||
<PluginSlot name="config:bottom" />
|
||||
<ConfirmDialog
|
||||
open={confirmReset}
|
||||
onCancel={() => setConfirmReset(false)}
|
||||
onConfirm={executeReset}
|
||||
title={t.config.confirmResetScope.replace(
|
||||
"{scope}",
|
||||
isSearching
|
||||
? t.config.searchResults
|
||||
: prettyCategoryName(activeCategory),
|
||||
)}
|
||||
description={`This will reset ${
|
||||
(isSearching ? searchMatchedFields : activeFields).length
|
||||
} field(s) to their default values.`}
|
||||
destructive
|
||||
confirmLabel={t.config.resetDefaults}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user