Skip to content

Commit 22f9702

Browse files
authored
Merge pull request #75 from BrainDriveAI/feature/settings-improvements-09-17-2025
Feature: Collapsible plugin panels and category counts in Settings page
2 parents c1eb5c1 + c24c6c2 commit 22f9702

File tree

1 file changed

+83
-25
lines changed

1 file changed

+83
-25
lines changed

frontend/src/pages/Settings.tsx

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@ import {
2626
Tooltip,
2727
Alert,
2828
CircularProgress,
29+
Collapse,
2930
} from '@mui/material';
3031
import DarkModeIcon from '@mui/icons-material/DarkMode';
3132
import LanguageIcon from '@mui/icons-material/Language';
3233
import StorageIcon from '@mui/icons-material/Storage';
3334
import AddIcon from '@mui/icons-material/Add';
3435
import CloseIcon from '@mui/icons-material/Close';
3536
import SettingsIcon from '@mui/icons-material/Settings';
37+
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
38+
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
3639
import { useTheme } from '../contexts/ServiceContext';
3740
import { getAllModules, getModuleById } from '../plugins';
3841
import { DynamicModuleConfig } from '../types/index';
@@ -83,6 +86,12 @@ const Settings = () => {
8386
const [isLoading, setIsLoading] = useState<boolean>(true);
8487
const [error, setError] = useState<string | null>(null);
8588

89+
// Collapsed state per plugin panel
90+
const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
91+
const pluginKey = (p: SettingsPlugin) => `${p.pluginId}-${p.moduleId}`;
92+
const toggleCollapsed = (key: string) =>
93+
setCollapsed((prev) => ({ ...prev, [key]: !prev[key] }));
94+
8695
// Handle theme change
8796
const handleThemeChange = () => {
8897
const newTheme =
@@ -382,6 +391,34 @@ const Settings = () => {
382391
);
383392
}, [activePlugins, selectedCategory]);
384393

394+
// Count of active plugins per category for display in Category dropdown
395+
const activeCountByCategory = useMemo(() => {
396+
const m: Record<string, number> = {};
397+
activePlugins.forEach((p) => {
398+
m[p.category] = (m[p.category] || 0) + 1;
399+
});
400+
return m;
401+
}, [activePlugins]);
402+
403+
// Ensure default collapsed state: new plugin panels start collapsed
404+
useEffect(() => {
405+
setCollapsed((prev) => {
406+
const next: Record<string, boolean> = { ...prev };
407+
// Add defaults for new active plugins
408+
activePlugins.forEach((p) => {
409+
const key = pluginKey(p);
410+
if (next[key] === undefined) next[key] = true; // collapsed by default
411+
});
412+
// Clean up keys for plugins no longer active
413+
Object.keys(next).forEach((k) => {
414+
if (!activePlugins.some((p) => pluginKey(p) === k)) {
415+
delete next[k];
416+
}
417+
});
418+
return next;
419+
});
420+
}, [activePlugins]);
421+
385422
// Add a plugin to the active list
386423
const handleAddPlugin = () => {
387424
if (!selectedPlugin) return;
@@ -446,12 +483,15 @@ const Settings = () => {
446483
id="category-select"
447484
value={selectedCategory}
448485
label="Category"
486+
renderValue={(value) =>
487+
`${value as string} (${activeCountByCategory[value as string] || 0})`
488+
}
449489
onChange={(e) => setSelectedCategory(e.target.value)}
450490
disabled={isLoading || categories.length === 0}
451491
>
452492
{categories.map((category) => (
453493
<MenuItem key={category} value={category}>
454-
{category}
494+
{category} ({activeCountByCategory[category] || 0})
455495
</MenuItem>
456496
))}
457497
</Select>
@@ -522,33 +562,51 @@ const Settings = () => {
522562
title={plugin.displayName}
523563
subheader={`Priority: ${plugin.priority}`}
524564
action={
525-
<Tooltip title="Remove">
526-
<IconButton
527-
aria-label="remove"
528-
onClick={() => handleRemovePlugin(plugin)}
529-
size="small"
530-
>
531-
<CloseIcon />
532-
</IconButton>
533-
</Tooltip>
565+
<>
566+
<Tooltip title={collapsed[pluginKey(plugin)] ? 'Expand' : 'Collapse'}>
567+
<IconButton
568+
aria-label="toggle"
569+
aria-expanded={!collapsed[pluginKey(plugin)]}
570+
onClick={() => toggleCollapsed(pluginKey(plugin))}
571+
size="small"
572+
>
573+
{collapsed[pluginKey(plugin)] ? (
574+
<ExpandMoreIcon />
575+
) : (
576+
<ExpandLessIcon />
577+
)}
578+
</IconButton>
579+
</Tooltip>
580+
<Tooltip title="Remove">
581+
<IconButton
582+
aria-label="remove"
583+
onClick={() => handleRemovePlugin(plugin)}
584+
size="small"
585+
>
586+
<CloseIcon />
587+
</IconButton>
588+
</Tooltip>
589+
</>
534590
}
535591
avatar={<SettingsIcon />}
536592
/>
537-
<CardContent sx={{ flexGrow: 1, overflow: 'auto', minHeight: '200px' }}>
538-
<LegacyModuleAdapter
539-
pluginId={plugin.pluginId}
540-
moduleId={plugin.moduleId}
541-
moduleName={plugin.moduleName}
542-
isLocal={false}
543-
useUnifiedRenderer={true}
544-
mode="published"
545-
lazyLoading={true}
546-
priority="normal"
547-
enableMigrationWarnings={process.env.NODE_ENV === 'development'}
548-
fallbackStrategy="on-error"
549-
performanceMonitoring={process.env.NODE_ENV === 'development'}
550-
/>
551-
</CardContent>
593+
<Collapse in={!collapsed[pluginKey(plugin)]} timeout="auto" unmountOnExit>
594+
<CardContent sx={{ flexGrow: 1, overflow: 'auto', minHeight: '200px' }}>
595+
<LegacyModuleAdapter
596+
pluginId={plugin.pluginId}
597+
moduleId={plugin.moduleId}
598+
moduleName={plugin.moduleName}
599+
isLocal={false}
600+
useUnifiedRenderer={true}
601+
mode="published"
602+
lazyLoading={true}
603+
priority="normal"
604+
enableMigrationWarnings={process.env.NODE_ENV === 'development'}
605+
fallbackStrategy="on-error"
606+
performanceMonitoring={process.env.NODE_ENV === 'development'}
607+
/>
608+
</CardContent>
609+
</Collapse>
552610
</Card>
553611
</Grid>
554612
))

0 commit comments

Comments
 (0)