Skip to content

Dashboard Studio: unified customization panel#5164

Merged
clubanderson merged 4 commits intomainfrom
feat/dashboard-studio-v2
Apr 7, 2026
Merged

Dashboard Studio: unified customization panel#5164
clubanderson merged 4 commits intomainfrom
feat/dashboard-studio-v2

Conversation

@clubanderson
Copy link
Copy Markdown
Collaborator

Summary

  • Reintroduces Dashboard Studio (originally 🚧 DO NOT MERGE: Dashboard Studio: unified customization panel #4365) after infinite loop fixes are in place
  • Card catalog, template gallery, AI suggestions, dashboard settings, widget export
  • Does NOT include the memoization removal that caused the infinite re-render loops
  • Includes TypeScript and test fixes for React 19 compatibility

Test plan

  • Verify dashboard switching still works smoothly
  • Open Studio panel from sidebar
  • Add/remove cards via card catalog
  • Switch between dashboard templates
  • Export widget
  • No "Maximum update depth exceeded" errors in console

- useWorkloadMonitor: wrap fetchData in useCallback with refs for params
- PDDisaggregation: memoize prefillIds/decodeIds, use string key for deps
- EPPRouting: remove unstable deps from effect
- GitHubActivity: remove fetchGitHubData from effect deps
- LatencyBreakdown/ThroughputComparison: fix empty key warnings

Signed-off-by: Andrew Anderson <[email protected]>
- Layout: wrap Outlet in Suspense to prevent full-page flash on navigation
- AlertsContext: memoize stats, activeAlerts, acknowledgedAlerts
- StackContext: memoize liveStacks, healthyStacks, disaggregatedStacks
- useInsightEnrichment: stabilize heuristicInsights dep with length key
- workloads: downgrade auth errors to console.debug (5 hooks)
- useTopology: suppress 401 errors in demo mode
- sseClient: skip retries on 401 auth errors

Signed-off-by: Andrew Anderson <[email protected]>
- Mock /prometheus/query with plausible vLLM metric values
- Return transparent PNG for github.com/*.png to avoid CSP violation
- Add avatars.githubusercontent.com passthrough

Signed-off-by: Andrew Anderson <[email protected]>
Reintroduces the Dashboard Studio (originally #4365) with all stability
fixes applied. The unified panel provides:
- Card catalog with search and category filtering
- Dashboard settings (name, layout, theme)
- Template gallery for quick dashboard creation
- AI suggestions for card placement
- Widget export functionality
- Navigation section for dashboard switching

Includes TypeScript fixes for React 19 compatibility and test fixes.
Does NOT include the memoization removal that caused infinite loops.

Signed-off-by: Andrew Anderson <[email protected]>
Copilot AI review requested due to automatic review settings April 7, 2026 05:09
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Apr 7, 2026
@kubestellar-prow
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 7, 2026

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit 1226590
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/69d49194048bbd000897b7ea
😎 Deploy Preview https://deploy-preview-5164.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

👋 Hey @clubanderson — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@clubanderson clubanderson merged commit 7cb9339 into main Apr 7, 2026
19 of 22 checks passed
@kubestellar-prow kubestellar-prow Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Apr 7, 2026
@kubestellar-prow kubestellar-prow Bot deleted the feat/dashboard-studio-v2 branch April 7, 2026 05:09
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

Thank you for your contribution! Your PR has been merged.

Check out what's new:

Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

Post-merge build verification passed

Both Go and frontend builds compiled successfully against merge commit 7cb9339c76ed07e52a76f2a5bdbee4c3acaa84ed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Reintroduces Dashboard Studio / Console Studio as a unified customization panel for dashboards, consolidating card browsing/AI suggestions/templates/navigation/widget export into a single experience while addressing prior infinite re-render concerns (memoization + dependency stabilization).

Changes:

  • Replaces legacy Add Card/Templates flows with the new DashboardCustomizer and updates FAB/keyboard shortcut behavior.
  • Adds “embedded” rendering mode to several existing modals/components to support inline rendering inside Console Studio.
  • Introduces multiple “stabilization” changes (memoization, effect dep adjustments, demo-mode auth-error suppression) across hooks/contexts/cards.

Reviewed changes

Copilot reviewed 48 out of 48 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
web/src/mocks/handlers.ts Adds GitHub avatar handling + Prometheus query mock for demo/test environments.
web/src/locales/en/common.json Adds Console Studio strings; renames some factory tab labels.
web/src/lib/sseClient.ts Skips SSE retries on auth-like errors in demo mode.
web/src/lib/modals/useModalNavigation.ts Prevents Escape bubbling to parent modals in nested-modal scenarios.
web/src/lib/dashboards/DashboardPage.tsx Swaps AddCard/Templates modals for DashboardCustomizer and wires URL params to sections.
web/src/hooks/useWorkloadMonitor.ts Refactors polling logic to use refs/callbacks to reduce effect churn.
web/src/hooks/useTopology.ts Suppresses expected demo-mode 401 logging noise.
web/src/hooks/useSidebarConfig.ts Adds preview/apply flow for “generate from behavior” sidebar config changes.
web/src/hooks/useInsightEnrichment.ts Attempts to reduce enrichment re-triggers by stabilizing effect deps.
web/src/hooks/useDashboardContext.tsx Extends dashboard context to support opening Studio by section + widget preselect.
web/src/hooks/mcp/workloads.ts Suppresses expected unauthenticated logging in demo mode.
web/src/contexts/StackContext.tsx Memoizes derived arrays to prevent unstable references/loops.
web/src/contexts/AlertsContext.tsx Memoizes derived alert stats/lists to stabilize context consumers.
web/src/components/widgets/WidgetExportModal.tsx Adds embedded mode for inline use in Console Studio.
web/src/components/layout/SidebarCustomizer.tsx Refactors dashboards/sidebar customization UI; adds preview/confirm apply flow and embedded rendering.
web/src/components/layout/Sidebar.tsx Routes “Add more dashboards” to open Console Studio on Dashboards section when available.
web/src/components/layout/Layout.tsx Wraps routed content (Outlet) in Suspense with skeleton fallback.
web/src/components/dashboard/templates.ts Replaces emoji icons with Lucide icon names for templates/categories.
web/src/components/dashboard/StatBlockFactoryModal.tsx Adds embedded mode + refactors modal content to reusable inner layout.
web/src/components/dashboard/shared/CardPreview.tsx New shared mini card visualization preview extracted for reuse.
web/src/components/dashboard/FloatingDashboardActions.tsx Adds unified “Studio” FAB mode (palette icon, Cmd/Ctrl+K) + inline undo/redo/reset.
web/src/components/dashboard/DashboardDropZone.tsx Adds droppable “Create New Dashboard” target for drag-and-drop.
web/src/components/dashboard/Dashboard.tsx Wires main dashboard to DashboardCustomizer; supports drop-to-create-dashboard; removes Templates/AddCard modals.
web/src/components/dashboard/customizer/sections/UnifiedCardsSection.tsx New unified cards view combining AI suggestions + catalog browsing.
web/src/components/dashboard/customizer/sections/TemplateGallerySection.tsx New embedded template/collection gallery section for Studio.
web/src/components/dashboard/customizer/sections/NavigationSection.tsx New embedded navigation management section using SidebarCustomizer.
web/src/components/dashboard/customizer/sections/DashboardSettingsSection.tsx New settings section (health/export/reset) component (not yet wired into Studio nav).
web/src/components/dashboard/customizer/sections/CardCatalogSection.tsx New extracted browse catalog section (legacy-style) with factories + recommended cards.
web/src/components/dashboard/customizer/sections/AISuggestionsSection.tsx New extracted AI suggestions section (legacy-style).
web/src/components/dashboard/customizer/SectionLayout.tsx New shared layout wrapper for Studio sections.
web/src/components/dashboard/customizer/PreviewPanel.tsx New right-side hover preview panel for cards.
web/src/components/dashboard/customizer/DashboardCustomizerSidebar.tsx New left navigation for Studio sections.
web/src/components/dashboard/customizer/DashboardCustomizer.tsx New Console Studio modal orchestration and section rendering.
web/src/components/dashboard/customizer/customizerNav.ts Defines Studio nav structure (currently hard-coded labels).
web/src/components/dashboard/customizer/AIAssistBar.tsx New reusable AI assist input (not yet broadly adopted by sections).
web/src/components/dashboard/customizer/tests/sections.test.tsx Adds basic export/smoke tests for new section components.
web/src/components/dashboard/customizer/tests/DashboardCustomizer.test.tsx Adds basic export/smoke tests for Studio components.
web/src/components/dashboard/customizer/tests/comprehensive.test.tsx Adds broader structural/export/data-module tests for Studio.
web/src/components/dashboard/CreateDashboardModal.tsx Adds embedded mode; switches template icons to Lucide via getIcon; removes health banner.
web/src/components/dashboard/CardFactoryModal.tsx Adds embedded mode and refactors layout; updates styling sizes.
web/src/components/cards/llmd/ThroughputComparison.tsx Makes legend keys robust when shortVariant is empty.
web/src/components/cards/llmd/PDDisaggregation.tsx Adjusts effect deps + memoizes derived ID lists to avoid loops.
web/src/components/cards/llmd/LatencyBreakdown.tsx Makes legend keys robust when shortVariant is empty.
web/src/components/cards/llmd/EPPRouting.tsx Adjusts effect deps to avoid loops (currently disables deps).
web/src/components/cards/GitHubActivity.tsx Adjusts polling effect deps to avoid re-render loops.
web/src/components/cards/CardWrapper.tsx Routes “Export as Widget” through Console Studio when available.

Comment on lines 135 to +155
@@ -142,7 +152,7 @@ export function useWorkloadMonitor(
intervalRef.current = null
}
}
}, [enabled, fetchData, refreshMs])
}, [fetchData])
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hook’s effect is guarded by initRef and only runs once. This breaks expected behavior when enabled or autoRefreshMs change after mount (e.g., the existing test case “resets state when disabled”), and it can leave the refresh interval running even after enabled becomes false.

Consider restoring an effect that reacts to enabled/refreshMs changes (clearing any existing interval and resetting state on disable), while still keeping fetchData stable via refs/useCallback if needed.

Copilot uses AI. Check for mistakes.
Comment on lines +260 to +270
// Stabilize with a length-based key to avoid re-firing on every new array reference
const insightsKey = heuristicInsights.length
useEffect(() => {
if (heuristicInsights.length > 0) {
if (insightsKey > 0) {
triggerEnrichment()
}
return () => {
if (requestRef.current) clearTimeout(requestRef.current)
}
}, [heuristicInsights, triggerEnrichment])
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [insightsKey, triggerEnrichment])
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insightsKey is derived only from heuristicInsights.length, so the enrichment request won’t re-trigger when the insights change but the length stays the same (e.g., rerendering with a different single insight). This breaks the debounce/reset behavior verified in useInsightEnrichment.test.ts (rapid updates test) and can leave enrichments stale.

Use a stable content-based key instead (e.g., hash/join of insight IDs + lastUpdated/severity), or keep the array in deps and stabilize upstream.

Copilot uses AI. Check for mistakes.
Comment on lines +262 to +263
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The periodic update effect is now useEffect(..., []) but reads stackServers from closure. If selectedStack, isDemoMode, or prometheusMetrics change, stackServers changes, but servers will keep updating from the initial stackServers only, leaving the card stale.

Include stackServers (or a stable key derived from it) in the dependency array, or store stackServers in a ref that the interval callback reads.

Suggested change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
}, [stackServers])

Copilot uses AI. Check for mistakes.
Comment on lines 699 to +741
// Update metrics — uses Prometheus when available, falls back to simulated
useEffect(() => {
const updateMetrics = () => {
const newMetrics: Record<string, { load: number; rps: number }> = {}
dynamicNodes.forEach(node => {
if (node.type !== 'source') {
// Try to get real metrics from Prometheus
const pods = nodePodMap[node.id]
const pod = pods?.[0]
const prom = pod && prometheusMetrics?.[pod]
if (prom) {
newMetrics[node.id] = {
load: Math.round(prom.kvCacheUsage * 100),
rps: Math.round(prom.throughputTps) }
} else {
newMetrics[node.id] = {
load: Math.floor(40 + Math.random() * 50),
rps: Math.floor(80 + Math.random() * 150) }
}
}
})
setNodeMetrics(newMetrics)

// Update history
setMetricsHistory(prev => {
const updated = { ...prev }
Object.entries(newMetrics).forEach(([id, m]) => {
if (!updated[id]) {
updated[id] = { load: [], rps: [] }
}
updated[id] = {
load: [...updated[id].load.slice(-19), m.load],
rps: [...updated[id].rps.slice(-19), m.rps] }
})
return updated
})
}

updateMetrics()
const interval = setInterval(updateMetrics, POLL_INTERVAL_FAST_MS)
return () => clearInterval(interval)
}, [dynamicNodes, nodePodMap, prometheusMetrics])
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metrics polling effect was changed to useEffect(..., []), but updateMetrics uses dynamicNodes, nodePodMap, and prometheusMetrics. With an empty dep array, the interval callback will keep using the initial values and won’t reflect topology changes or new Prometheus data.

Consider including a stable deps key (e.g., dynamicNodesKey, nodePodMapKey, and prometheusMetricsKey) or reading the latest values from refs inside updateMetrics instead of suppressing exhaustive-deps.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +64
interface DashboardCustomizerProps {
isOpen: boolean
onClose: () => void
/** Name of the dashboard being customized */
dashboardName?: string
onAddCards: (cards: CardSuggestion[]) => void
existingCardTypes?: string[]
initialSection?: CustomizerSection
/** Pre-selected card type for widget export (from card menu "Export as Widget") */
initialWidgetCardType?: string
initialSearch?: string
onApplyTemplate?: (template: DashboardTemplate) => void
onExport?: () => void
onReset?: () => void
isCustomized?: boolean
onUndo?: () => void
onRedo?: () => void
canUndo?: boolean
canRedo?: boolean
}

const SECTIONS_WITH_PREVIEW = new Set<CustomizerSection>(['cards', 'collections'])

export function DashboardCustomizer({
isOpen,
onClose,
dashboardName,
onAddCards,
existingCardTypes = [],
initialSection,
initialWidgetCardType,
initialSearch = '',
onApplyTemplate,
onReset,
isCustomized = false,
onUndo,
onRedo,
canUndo = false,
canRedo = false,
}: DashboardCustomizerProps) {
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DashboardCustomizerProps includes onExport, but the component never destructures or uses it, so the export action passed from Dashboard.tsx is currently unreachable from Console Studio. There’s also a DashboardSettingsSection component added in this PR, but it isn’t wired into the Studio nav.

Either add a Settings/Export section (and nav item) that uses onExport/onReset, or remove the prop to avoid a false API surface.

Copilot uses AI. Check for mistakes.
Comment on lines 291 to 303
if (sortedPaths.length > 0) {
generateFromBehavior(sortedPaths)
setGenerationResult(t('sidebar.customizer.analyzed', { count: navHistory.length }))
const preview = previewGenerateFromBehavior(sortedPaths)
if (preview.changes.length === 1 && preview.changes[0] === 'No changes needed') {
setGenerationResult('No changes needed — your sidebar already matches your usage.')
dismissTimerRef.current = setTimeout(() => setGenerationResult(null), AUTO_DISMISS_MS)
} else {
setPendingChanges(preview)
}
} else {
setGenerationResult(t('sidebar.customizer.notEnoughData'))
const AUTO_DISMISS_MS = 5000
dismissTimerRef.current = setTimeout(() => setGenerationResult(null), AUTO_DISMISS_MS)
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many user-facing strings in this updated SidebarCustomizer are now hard-coded (e.g., “No changes needed — …”, “Applied X changes”, “Reset Sidebar”, placeholders/titles). This bypasses the existing i18n approach used elsewhere in the component (t('sidebar.customizer.*')) and makes localization inconsistent.

Prefer adding translation keys and using t(...) for these strings; also avoid redeclaring AUTO_DISMISS_MS inside the else-branch since a module-level constant already exists.

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +39
label: string
icon: LucideIcon
/** Show a subtle divider line above this item */
dividerBefore?: boolean
}

export const CUSTOMIZER_NAV: NavItem[] = [
{ id: 'cards', label: 'Add Cards', icon: LayoutGrid },
{ id: 'collections', label: 'Add Card Collections', icon: Layout },
{ id: 'dashboards', label: 'Manage Dashboards', icon: LayoutDashboard },
{ id: 'widgets', label: 'Export Widgets', icon: Download },
{ id: 'create-dashboard', label: 'Create Custom Dashboard', icon: FolderPlus, dividerBefore: true },
{ id: 'card-factory', label: 'Create Custom Card', icon: Wand2 },
{ id: 'stat-factory', label: 'Create Stat Blocks', icon: Activity },
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Console Studio nav labels are hard-coded English strings. Since the app uses i18next (and this PR adds dashboard.studio.* locale keys), these labels should be sourced from translations to keep localization consistent.

Consider storing translation keys (not labels) in CUSTOMIZER_NAV and resolving them with t(...) in the sidebar component.

Suggested change
label: string
icon: LucideIcon
/** Show a subtle divider line above this item */
dividerBefore?: boolean
}
export const CUSTOMIZER_NAV: NavItem[] = [
{ id: 'cards', label: 'Add Cards', icon: LayoutGrid },
{ id: 'collections', label: 'Add Card Collections', icon: Layout },
{ id: 'dashboards', label: 'Manage Dashboards', icon: LayoutDashboard },
{ id: 'widgets', label: 'Export Widgets', icon: Download },
{ id: 'create-dashboard', label: 'Create Custom Dashboard', icon: FolderPlus, dividerBefore: true },
{ id: 'card-factory', label: 'Create Custom Card', icon: Wand2 },
{ id: 'stat-factory', label: 'Create Stat Blocks', icon: Activity },
labelKey: string
icon: LucideIcon
/** Show a subtle divider line above this item */
dividerBefore?: boolean
}
export const CUSTOMIZER_NAV: NavItem[] = [
{ id: 'cards', labelKey: 'dashboard.studio.addCards', icon: LayoutGrid },
{ id: 'collections', labelKey: 'dashboard.studio.addCardCollections', icon: Layout },
{ id: 'dashboards', labelKey: 'dashboard.studio.manageDashboards', icon: LayoutDashboard },
{ id: 'widgets', labelKey: 'dashboard.studio.exportWidgets', icon: Download },
{ id: 'create-dashboard', labelKey: 'dashboard.studio.createCustomDashboard', icon: FolderPlus, dividerBefore: true },
{ id: 'card-factory', labelKey: 'dashboard.studio.createCustomCard', icon: Wand2 },
{ id: 'stat-factory', labelKey: 'dashboard.studio.createStatBlocks', icon: Activity },

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +241
{/* Single unified search bar */}
<div className="mb-3">
<p className="text-xs text-muted-foreground mb-2">
Search the card catalog or describe what you need — cards will be added to the {dashboardLabel} dashboard
</p>
<div className="flex gap-2">
<div className="relative flex-1">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
<input
ref={searchInputRef}
type="text"
value={browseSearch}
onChange={(e) => handleUnifiedSearch(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && browseSearch.trim() && handleGenerateWithQuery(browseSearch)}
placeholder="Search cards or describe what you want to monitor..."
className="w-full pl-10 pr-4 py-2 bg-secondary rounded-lg text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-purple-500/50"
/>
</div>
<button
onClick={() => handleGenerateWithQuery(browseSearch)}
disabled={!browseSearch.trim() || isGenerating}
className="px-3 py-2 bg-gradient-ks text-primary-foreground rounded-lg text-sm font-medium disabled:opacity-50 flex items-center gap-1.5 whitespace-nowrap"
title="Use AI to suggest cards based on your query"
>
{isGenerating ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Sparkles className="w-3.5 h-3.5" />}
{isGenerating ? 'Thinking...' : 'AI Suggest'}
</button>
</div>
{/* Quick AI prompts — click to auto-generate card suggestions */}
<div className="flex flex-wrap items-center gap-1.5 mt-2">
<span className="text-xs text-muted-foreground mr-1">Try:</span>
{aiExamples.map((example) => (
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section introduces several new user-facing strings as literals (e.g., helper text, placeholders, button labels like “AI Suggest”/“Thinking…”, “Try:”, “Clear & show all cards”). Given the existing i18n usage (t(...)) and the new dashboard.studio locale entries, these should be translated to avoid regressions for non-English locales.

Consider replacing these literals with t(...) keys (with sensible defaults) and/or moving them into common.json.

Copilot uses AI. Check for mistakes.
Comment on lines +122 to +135
{activeSection === 'collections' && onApplyTemplate && (
<TemplateGallerySection
onReplaceWithTemplate={handleApplyTemplate}
onAddTemplate={(template) => {
// Convert template cards to CardSuggestion format and add
const cards = (template.cards || []).map(c => ({
type: c.card_type,
title: c.card_type,
description: '',
visualization: 'status' as const,
config: c.config || {},
}))
handleAddCards(cards)
}}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using “Add” for a collection, template cards are converted to CardSuggestion with title: c.card_type and description: ''. In Dashboard.tsx, handleAddCards uses s.title as the card title, so these cards will show raw type IDs instead of the template’s intended tc.title (and lose descriptions).

Consider passing through c.title (or a formatted title) and description when building the suggestions.

Copilot uses AI. Check for mistakes.
@clubanderson
Copy link
Copy Markdown
Collaborator Author

🔄 Auto-Applying Copilot Code Review

Copilot code review found 2 code suggestion(s) and 7 general comment(s).

@copilot Please apply all of the following code review suggestions:

  • web/src/components/cards/llmd/PDDisaggregation.tsx (line 263): }, [stackServers])
  • web/src/components/dashboard/customizer/customizerNav.ts (line 39): labelKey: string icon: LucideIcon /** Show a subtle divider line above this ...

Also address these general comments:

  • web/src/hooks/useWorkloadMonitor.ts (line 155): The hook’s effect is guarded by initRef and only runs once. This breaks expected behavior when enabled or `autoRefresh
  • web/src/hooks/useInsightEnrichment.ts (line 270): insightsKey is derived only from heuristicInsights.length, so the enrichment request won’t re-trigger when the insig
  • web/src/components/cards/llmd/EPPRouting.tsx (line 741): The metrics polling effect was changed to useEffect(..., []), but updateMetrics uses dynamicNodes, nodePodMap, a
  • web/src/components/dashboard/customizer/DashboardCustomizer.tsx (line 64): DashboardCustomizerProps includes onExport, but the component never destructures or uses it, so the export action pa
  • web/src/components/layout/SidebarCustomizer.tsx (line 303): Many user-facing strings in this updated SidebarCustomizer are now hard-coded (e.g., “No changes needed — …”, “Applied X
  • web/src/components/dashboard/customizer/sections/UnifiedCardsSection.tsx (line 241): This section introduces several new user-facing strings as literals (e.g., helper text, placeholders, button labels like
  • web/src/components/dashboard/customizer/DashboardCustomizer.tsx (line 135): When using “Add” for a collection, template cards are converted to CardSuggestion with title: c.card_type and `descr

Push all fixes in a single commit. Run cd web && npm run build && npm run lint before committing.


Auto-generated by copilot-review-apply workflow.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

✅ Post-Merge Verification: passed

Commit: 7cb9339c76ed07e52a76f2a5bdbee4c3acaa84ed
Specs run: Dashboard.spec.ts navbar-responsive.spec.ts smoke.spec.ts
Report: https://github.com/kubestellar/console/actions/runs/24065419483

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants