diff --git a/docs/implplan/SPRINT_20260307_018_FE_search_primary_entry_consolidation.md b/docs/implplan/SPRINT_20260307_018_FE_search_primary_entry_consolidation.md index b7b0c764a..d7cd9b3b2 100644 --- a/docs/implplan/SPRINT_20260307_018_FE_search_primary_entry_consolidation.md +++ b/docs/implplan/SPRINT_20260307_018_FE_search_primary_entry_consolidation.md @@ -19,7 +19,7 @@ ## Delivery Tracker ### FE-ZL-001 - Search-first top-bar entry with secondary chat launcher -Status: TODO +Status: DONE Dependency: none Owners: Developer (FE) Task description: @@ -27,12 +27,12 @@ Task description: - Opening chat must inherit page context and current query when present. Completion criteria: -- [ ] Search remains the primary focus target in the header. -- [ ] AdvisoryAI launches from a secondary icon/button beside search. -- [ ] Existing chat handoff still works from result cards and answer panels. +- [x] Search remains the primary focus target in the header. +- [x] AdvisoryAI launches from a secondary icon/button beside search. +- [x] Existing chat handoff still works from result cards and answer panels. ### FE-ZL-002 - Remove explicit mode/scope/recovery controls -Status: TODO +Status: DONE Dependency: FE-ZL-001 Owners: Developer (FE) Task description: @@ -40,13 +40,13 @@ Task description: - Move `Did you mean` immediately under the input. Completion criteria: -- [ ] No explicit mode control remains in the search panel. -- [ ] No explicit scope toggle remains in the search panel. -- [ ] No recovery panel remains in empty-result states. -- [ ] `Did you mean` renders directly under the input when present. +- [x] No explicit mode control remains in the search panel. +- [x] No explicit scope toggle remains in the search panel. +- [x] No recovery panel remains in empty-result states. +- [x] `Did you mean` renders directly under the input when present. ### FE-ZL-003 - History cleanup and low-emphasis clear action -Status: TODO +Status: DONE Dependency: FE-ZL-002 Owners: Developer (FE) Task description: @@ -54,32 +54,34 @@ Task description: - Replace the current clear-history button with a discrete icon action. Completion criteria: -- [ ] Recent history excludes searches with zero results. -- [ ] Clear-history affordance is icon-based and visually low emphasis. -- [ ] Search history tests cover the new behavior. +- [x] Recent history excludes searches with zero results. +- [x] Clear-history affordance is icon-based and visually low emphasis. +- [x] Search history tests cover the new behavior. ### FE-ZL-004 - Focused FE verification -Status: TODO +Status: DONE Dependency: FE-ZL-003 Owners: Test Automation Task description: - Add or update Angular and Playwright tests for the consolidated UI model. Completion criteria: -- [ ] Unit tests cover removed controls and new placement rules. -- [ ] Playwright covers the new top-bar, history, and `Did you mean` behavior. -- [ ] Tests do not rely on deprecated `mode` or `scope` UI controls. +- [x] Unit tests cover removed controls and new placement rules. +- [x] Playwright covers the new top-bar, history, and `Did you mean` behavior. +- [x] Tests do not rely on deprecated `mode` or `scope` UI controls. ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | | 2026-03-07 | Sprint created from the zero-learning search strategy. | Project Manager | +| 2026-03-07 | Implemented the search-first shell: added the secondary AdvisoryAI launcher, removed explicit mode/scope/recovery controls, moved `Did you mean` under the input, migrated recent history to success-only storage, and updated focused Angular plus Playwright coverage. Commands: `npm test -- --include src/tests/global_search/global-search.component.spec.ts`; `npx playwright test tests/e2e/unified-search-contextual-suggestions.e2e.spec.ts tests/e2e/unified-search-self-serve-answer-panel.e2e.spec.ts tests/e2e/unified-search-experience-quality.e2e.spec.ts --config playwright.config.ts`. Results: `22/22` unit tests passed and `11/11` Playwright tests passed. | Developer / Test Automation | ## Decisions & Risks - Decision: the user should not be asked to choose a search mode before entering a query. - Decision: page scope becomes implicit UX, not an explicit control. - Risk: removing explicit controls may expose gaps in backend ranking that modes were previously masking. - Mitigation: phase 2 adds implicit-scope weighting and answer blending on the backend. +- Verification note: focused Playwright runs still log an unrelated Angular `NG0602` console error from `PlatformContextUrlSyncService.initialize` plus several refused background requests. The targeted search flows remained green, but that runtime issue should be handled separately by the stabilization workstream. ## Next Checkpoints - 2026-03-08: Implement FE-ZL-001 through FE-ZL-003. diff --git a/src/Web/StellaOps.Web/src/app/layout/global-search/global-search.component.ts b/src/Web/StellaOps.Web/src/app/layout/global-search/global-search.component.ts index d41d931c6..912930635 100644 --- a/src/Web/StellaOps.Web/src/app/layout/global-search/global-search.component.ts +++ b/src/Web/StellaOps.Web/src/app/layout/global-search/global-search.component.ts @@ -23,8 +23,6 @@ import { UnifiedSearchClient } from '../../core/api/unified-search.client'; import type { EntityCard, EntityCardAction, - SearchRefinement, - SynthesisResult, UnifiedSearchResponse, UnifiedSearchDomain, } from '../../core/api/unified-search.models'; @@ -33,25 +31,18 @@ import { EntityCardComponent } from '../../shared/components/entity-card/entity- import { SynthesisPanelComponent } from '../../shared/components/synthesis-panel/synthesis-panel.component'; import { AmbientContextService } from '../../core/services/ambient-context.service'; import { SearchChatContextService } from '../../core/services/search-chat-context.service'; -import { - SearchExperienceModeService, - type SearchExperienceMode, -} from '../../core/services/search-experience-mode.service'; import { I18nService } from '../../core/i18n'; import { normalizeSearchActionRoute } from './search-route-matrix'; type SearchDomainFilter = 'all' | UnifiedSearchDomain; -type SearchScopeMode = 'page' | 'global'; type SearchSuggestionView = { query: string; reason: string; kind: 'page' | 'recent' | 'strategy'; - preferredModes?: readonly SearchExperienceMode[]; }; type SearchQuestionView = { query: string; kind: 'page' | 'clarify' | 'recent'; - preferredModes?: readonly SearchExperienceMode[]; }; type SearchContextPanelView = { title: string; @@ -62,11 +53,6 @@ type SearchContextPanelView = { value: string; }>; }; -type RescueActionView = { - id: 'scope' | 'related' | 'reformulate' | 'page-context'; - label: string; - description: string; -}; type SearchAnswerView = { status: 'grounded' | 'clarify' | 'insufficient'; eyebrow: string; @@ -108,6 +94,19 @@ type SearchAnswerView = { aria-autocomplete="list" /> + + @@ -120,38 +119,20 @@ type SearchAnswerView = { } -
-
-
{{ t('ui.search.mode.label', 'Mode') }}
-
{{ experienceModeDescription() }}
+ @if (query().trim().length >= 1 && searchResponse()?.suggestions?.length) { +
+ {{ t('ui.search.did_you_mean_label', 'Did you mean:') }} + @for (suggestion of searchResponse()!.suggestions!; track suggestion.text) { + + }
-
-
- @for (mode of experienceModeOptions(); track mode.id) { - - } -
- -
-
+ } @if (searchAnswer(); as answer) {
{{ t('ui.search.loading', 'Searching...') }}
} @else if (query().trim().length >= 1 && cards().length === 0) {
{{ t('ui.search.no_results', 'No results found') }}
- @if (searchResponse()?.suggestions?.length) { -
- {{ t('ui.search.did_you_mean_label', 'Did you mean:') }} - @for (suggestion of searchResponse()!.suggestions!; track suggestion.text) { - - } -
- } - @if (refinements().length > 0) { -
- {{ t('ui.search.try_also_label', 'Try also:') }} - @for (r of refinements(); track r.text) { - - } -
- } -
-
{{ t('ui.search.rescue.label', 'Recover this search') }}
-
- @for (action of rescueActions(); track action.id) { - - } -
-
} @else if (query().trim().length >= 1) {
@for (filter of availableDomainFilters(); track filter) { @@ -285,33 +224,6 @@ type SearchAnswerView = { }
- @if (searchResponse()?.suggestions?.length) { -
- {{ t('ui.search.did_you_mean_label', 'Did you mean:') }} - @for (suggestion of searchResponse()!.suggestions!; track suggestion.text) { - - } -
- } - @if (refinements().length > 0) { -
- {{ t('ui.search.try_also_label', 'Try also:') }} - @for (r of refinements(); track r.text) { - - } -
- } -
@for (card of filteredCards(); track card.entityKey; let i = $index) {
{{ t('ui.search.recent_label', 'Recent') }}
- +
@for (recent of recentSearches(); track recent; let i = $index) {