Skip to content

🐛 fix: missions search, mission state UX, namespace dropdown#3962

Merged
clubanderson merged 1 commit intomainfrom
fix/frontend-bugs-batch2
Mar 31, 2026
Merged

🐛 fix: missions search, mission state UX, namespace dropdown#3962
clubanderson merged 1 commit intomainfrom
fix/frontend-bugs-batch2

Conversation

@clubanderson
Copy link
Copy Markdown
Collaborator

Summary

  • No Search Option in AI Missions List #3944 — Mission search: Added a search/filter input at the top of the AI Missions sidebar list. Filters both saved and active missions by title and description in real-time. Shows a "no results" state when the query matches nothing. Includes a clear button.
  • Better UX for users using AI missions #3917 — Mission state UX without AI: Saved missions now display their imported steps (title + description) in a structured list view, so users can review what the mission will do without needing an AI provider connected. The "Run Mission" button remains prominent above the steps.
  • bug: my namespace does not appear in the menu #3945 — Namespace dropdown: The GPU reservation namespace dropdown now merges namespaces from the cluster cache (populated during health checks) with pod-based namespaces from the REST API fallback. This ensures namespaces that exist but have no running pods still appear in the dropdown.

Changes

File Change
web/src/components/layout/mission-sidebar/MissionSidebar.tsx Search input + filtering logic for mission list
web/src/components/layout/mission-sidebar/MissionChat.tsx Mission steps overview panel for saved missions
web/src/hooks/mcp/namespaces.ts Merge cluster cache with pod-based namespace discovery

Test plan

  • Open AI Missions sidebar with 2+ missions, verify search input appears and filters by title/description
  • Clear search with X button, verify all missions reappear
  • Import a community mission (e.g. install-prometheus), open it — verify steps are shown below Run button
  • Select "None" as AI agent, verify steps are still visible
  • Open GPU Reservations, select a cluster, verify namespace dropdown includes namespaces without pods
  • Build passes: npm run build

Fixes #3944 #3917 #3945

- Add search/filter input to the AI Missions sidebar list so users can
  quickly find missions by title or description (#3944)
- Show imported mission steps in the saved-mission view so users can
  review the mission plan without requiring an AI provider (#3917)
- Merge cluster cache namespaces with pod-based namespaces in the REST
  API fallback so namespaces without running pods still appear in the
  GPU reservation namespace dropdown (#3945)

Fixes #3944 #3917 #3945

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Copilot AI review requested due to automatic review settings March 31, 2026 12:42
@kubestellar-prow kubestellar-prow bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Mar 31, 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

@kubestellar-prow kubestellar-prow bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Mar 31, 2026
@github-actions
Copy link
Copy Markdown
Contributor

👋 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.

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 31, 2026

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit ef006b3
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/69cbc157ca5e6a000843c44e
😎 Deploy Preview https://deploy-preview-3962.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.

@clubanderson clubanderson merged commit 697496b into main Mar 31, 2026
21 of 23 checks passed
@kubestellar-prow kubestellar-prow bot deleted the fix/frontend-bugs-batch2 branch March 31, 2026 12:45
@github-actions
Copy link
Copy Markdown
Contributor

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

Check out what's new:

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

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

This PR improves the AI Missions UX and fixes a namespace discovery gap by adding mission list search, showing saved mission steps without requiring an AI provider, and enhancing namespace dropdown population by merging cached and live-discovered namespaces.

Changes:

  • Added a mission search input to filter saved and active missions in real time, including a “no results” state.
  • Added an inline “Mission Steps” overview panel for saved missions with no conversation, so users can review steps without an AI provider.
  • Updated namespace discovery to merge cluster-cache namespaces with pod-discovered namespaces so namespaces without pods still appear.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
web/src/components/layout/mission-sidebar/MissionSidebar.tsx Adds mission search state/UI and applies filtering to mission lists.
web/src/components/layout/mission-sidebar/MissionChat.tsx Displays imported mission steps for saved missions before any chat starts.
web/src/hooks/mcp/namespaces.ts Merges cached namespaces with REST pod-discovered namespaces for dropdown completeness.

Comment on lines +295 to +302
// Split missions into saved (library) and active, applying search filter
const matchesSearch = useCallback((m: Mission) => {
if (!missionSearchQuery.trim()) return true
const q = missionSearchQuery.toLowerCase()
return m.title.toLowerCase().includes(q) || m.description.toLowerCase().includes(q)
}, [missionSearchQuery])
const savedMissions = missions.filter(m => m.status === 'saved' && matchesSearch(m))
const activeMissions = missions.filter(m => m.status !== 'saved' && matchesSearch(m))
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

Filtering savedMissions / activeMissions at the source changes their semantics across the component (they’re used for more than just rendering the list). For example, the Saved Mission Detail modal’s onImport logic later searches within savedMissions; with an active search query (or after a rename while the modal is open), the mission may no longer be present and the action can silently no-op. Consider keeping unfiltered savedMissionsAll/activeMissionsAll for internal logic and deriving separate savedMissionsFiltered/activeMissionsFiltered for list rendering only.

Copilot uses AI. Check for mistakes.
Comment on lines +297 to +299
if (!missionSearchQuery.trim()) return true
const q = missionSearchQuery.toLowerCase()
return m.title.toLowerCase().includes(q) || m.description.toLowerCase().includes(q)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

The search query is checked with trim() for emptiness, but the value used for matching isn’t trimmed. Queries with leading/trailing whitespace (e.g., pasted text) won’t match even when the underlying terms do. Normalize the query once (e.g., missionSearchQuery.trim().toLowerCase()) before running includes.

Suggested change
if (!missionSearchQuery.trim()) return true
const q = missionSearchQuery.toLowerCase()
return m.title.toLowerCase().includes(q) || m.description.toLowerCase().includes(q)
const normalizedQuery = missionSearchQuery.trim().toLowerCase()
if (!normalizedQuery) return true
return (
m.title.toLowerCase().includes(normalizedQuery) ||
m.description.toLowerCase().includes(normalizedQuery)
)

Copilot uses AI. Check for mistakes.
Comment on lines +937 to +940
<button
onClick={() => setMissionSearchQuery('')}
className="absolute right-3.5 top-1/2 -translate-y-1/2 p-0.5 hover:bg-secondary rounded transition-colors"
title={t('common.clear', { defaultValue: 'Clear' })}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

The clear (X) control is an icon-only <button> with only a title. For screen readers this should have an explicit accessible name (e.g., aria-label) and should be type="button" to avoid accidental form submission if this component is ever rendered inside a <form>. Alternatively, use the shared <Button> component which already handles aria-label defaults.

Suggested change
<button
onClick={() => setMissionSearchQuery('')}
className="absolute right-3.5 top-1/2 -translate-y-1/2 p-0.5 hover:bg-secondary rounded transition-colors"
title={t('common.clear', { defaultValue: 'Clear' })}
<button
type="button"
onClick={() => setMissionSearchQuery('')}
className="absolute right-3.5 top-1/2 -translate-y-1/2 p-0.5 hover:bg-secondary rounded transition-colors"
title={t('common.clear', { defaultValue: 'Clear' })}
aria-label={t('common.clear', { defaultValue: 'Clear' })}

Copilot uses AI. Check for mistakes.
Comment on lines +110 to 137
// Fall back to REST API — merge pod-based namespaces with cluster cache
// to include namespaces that have no running pods (#3945)
try {
const { data } = await api.get<{ pods: PodInfo[] }>(`/api/mcp/pods?cluster=${encodeURIComponent(cluster)}`)
const nsSet = new Set<string>()
data.pods?.forEach(pod => {
if (pod.namespace) nsSet.add(pod.namespace)
})
setNamespaces(Array.from(nsSet).sort())
setError(null)
} catch (err) {
// Try cluster cache namespaces as last resort

// Seed with cluster cache namespaces (discovered during health checks)
// so namespaces without pods still appear in the dropdown
const cachedCluster = clusterCacheRef.clusters.find(c => c.name === cluster)
if (cachedCluster?.namespaces && cachedCluster.namespaces.length > 0) {
setNamespaces(cachedCluster.namespaces)
if (cachedCluster?.namespaces) {
for (const ns of cachedCluster.namespaces) {
nsSet.add(ns)
}
}

// Also add namespaces from pods (may discover recently created namespaces
// that the cache hasn't seen yet)
try {
const { data } = await api.get<{ pods: PodInfo[] }>(`/api/mcp/pods?cluster=${encodeURIComponent(cluster)}`)
for (const pod of (data.pods || [])) {
if (pod.namespace) nsSet.add(pod.namespace)
}
} catch {
// Non-fatal: we may still have cache namespaces above
}

if (nsSet.size > 0) {
setNamespaces(Array.from(nsSet).sort())
setError(null)
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This change introduces new behavior (merging cached cluster namespaces with pod-discovered namespaces) but the existing useNamespaces unit tests don’t cover the merge case. Add a test that seeds clusterCacheRef with namespaces not present in pods and asserts they still appear in the returned list (and that the result is sorted/deduped).

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 2 general comment(s).

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

  • web/src/components/layout/mission-sidebar/MissionSidebar.tsx (line 299): const normalizedQuery = missionSearchQuery.trim().toLowerCase() if (!normali...
  • web/src/components/layout/mission-sidebar/MissionSidebar.tsx (line 940): <button type="button" onClick={() => setMiss...

Also address these general comments:

  • web/src/components/layout/mission-sidebar/MissionSidebar.tsx (line 302): Filtering savedMissions / activeMissions at the source changes their semantics across the component (they’re used fo
  • web/src/hooks/mcp/namespaces.ts (line 137): This change introduces new behavior (merging cached cluster namespaces with pod-discovered namespaces) but the existing

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.

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/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No Search Option in AI Missions List

3 participants