-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Story: Configurable Metadata Panel Display Order
Feature: Metadata Panel Display Order
Part of: #EPIC
[Conversation Reference: "Groups finding 6 -- metadata panel display order prioritizes KB fields over generic wiki fields"]
[Conversation Reference: "User said 'defaults match current behavior for backward compatibility' and 'good regression tests for every conceptual change'"]
Story Overview
As a CIDX server administrator,
I want to control the display order of metadata fields in the article metadata panel,
So that I can prioritize the fields most relevant to my users.
Objective: Add a metadata_display_order setting to WikiConfig (comma-separated string) that controls the order in which fields appear in the metadata panel. The default value is "" (empty string), which preserves current behavior: article_number first (if present), remaining fields in dict iteration order (YAML frontmatter key order). When an admin sets a non-empty order string, prepare_metadata_context() sorts its output tuples according to the configured order. Fields not listed in the order string appear after the listed ones, sorted alphabetically. Fields disabled by Story 1 toggles are auto-excluded regardless of their presence in the order string.
User Value: Administrators can reorder the metadata panel to prioritize fields relevant to their team (e.g., "author,modified,created" for a development wiki) instead of the default order. The default (empty string) preserves current behavior exactly. Setting a custom order string gives full control over field positioning.
Acceptance Criteria Summary: Comma-separated order string controls field ordering; default empty string preserves current iteration order; unlisted fields appear after listed ones alphabetically; disabled fields auto-excluded; edge cases handled gracefully.
Implementation Status
-
metadata_display_ordercomma-separated string field added toWikiConfigwith default""(empty = preserve current iteration order) -
prepare_metadata_context()updated to sort output tuples according to configured order - Unlisted fields appended after listed ones, sorted alphabetically
- Disabled fields (from Story 1 toggles) auto-excluded regardless of order string
- Config Web UI "Wiki" section extended with text input for display order
- Unit tests: default order matches current field ordering
- Unit tests: custom order reorders fields correctly
- Unit tests: unlisted fields appear after listed ones alphabetically
- Unit tests: disabled field exclusion regardless of order
- Unit tests: empty order string, duplicate fields, nonexistent fields
- Config persistence round-trip test
- Code review approved
- Manual E2E testing completed
Completion: 0/13 tasks complete (0%)
Algorithm
WikiConfig.metadata_display_order (comma-separated string):
Default: "" (empty string = preserve current iteration order)
prepare_metadata_context(metadata, ..., wiki_config=None):
# ... existing field building and conditional exclusion logic (Story 1) ...
# At this point we have a list of tuples: [(label, value), ...]
# Each tuple was built from a metadata key
IF wiki_config is None:
# Backward compat: use current ordering
# article_number first (already handled by existing code), rest in iteration order
RETURN result
IF wiki_config.metadata_display_order is "" (empty or whitespace-only):
# Empty order string = preserve current iteration order (same as wiki_config=None)
RETURN result
# Parse order string (only reached when admin explicitly sets a non-empty order)
order_list = [
field.strip().lower()
FOR field IN wiki_config.metadata_display_order.split(",")
IF field.strip()
]
# Remove duplicates while preserving order
seen = set()
unique_order = []
FOR field IN order_list:
IF field NOT IN seen:
unique_order.append(field)
seen.add(field)
# Build a key-to-tuple mapping
# We need to track which metadata key produced each tuple
# Modify result building to track keys alongside tuples
keyed_result = [] # List of (metadata_key, label, value)
... (build keyed_result during field iteration) ...
# Sort by configured order
ordered_output = []
remaining = list(keyed_result)
FOR order_key IN unique_order:
FOR item IN remaining[:]: # copy to allow removal during iteration
IF item.metadata_key == order_key:
ordered_output.append((item.label, item.value))
remaining.remove(item)
BREAK # Each field appears only once
# Append unlisted fields sorted alphabetically by metadata key
remaining.sort(key=lambda item: item.metadata_key)
FOR item IN remaining:
ordered_output.append((item.label, item.value))
RETURN ordered_output
Note: Fields disabled by Story 1 toggles (enable_article_number=False, etc.)
are excluded BEFORE ordering runs, so they never appear in the result
regardless of their presence in metadata_display_order.
Acceptance Criteria
AC1: Default Order -- Empty String Preserves Current Behavior
Given the wiki_config.metadata_display_order uses the default value "" (empty string)
And an article has front matter with article_number, publication_status, created, modified, author, and visibility
When prepare_metadata_context() builds the metadata panel
Then the fields appear in the current codebase order:
article_number first (if present), remaining fields in dict iteration order (YAML key order)
And this is identical to the behavior when wiki_config=None
And no custom sorting is appliedAC2: Custom Order -- Reordered Fields
Given the wiki_config.metadata_display_order is "author,modified,created,visibility"
And an article has front matter with author, modified, created, visibility, and article_number
When prepare_metadata_context() builds the metadata panel
Then the fields appear in this order:
1. author
2. modified
3. created
4. visibility
5. article_number (unlisted, appended alphabetically)AC3: Unlisted Fields -- Appear After Listed Ones Alphabetically
Given the wiki_config.metadata_display_order is "created,modified"
And an article has front matter with created, modified, author, visibility, and article_number
When prepare_metadata_context() builds the metadata panel
Then the fields appear in this order:
1. created (listed)
2. modified (listed)
3. article_number (unlisted, alphabetically first)
4. author (unlisted, alphabetically second)
5. visibility (unlisted, alphabetically third)AC4: Disabled Field Exclusion -- Regardless of Order
Given the wiki_config.enable_article_number is False (from Story 1)
And the wiki_config.metadata_display_order includes "article_number" in the string
And an article has article_number in front matter
When prepare_metadata_context() builds the metadata panel
Then article_number does NOT appear in the panel
And the remaining fields are ordered according to the configured order
And no gap or placeholder appears where article_number would have beenAC5: Disabled Publication Status -- Regardless of Order
Given the wiki_config.enable_publication_status is False (from Story 1)
And the wiki_config.metadata_display_order includes "publication_status" in the string
And an article has publication_status in front matter
When prepare_metadata_context() builds the metadata panel
Then publication_status does NOT appear in the panel
And the remaining fields are ordered according to the configured orderAC6: Empty Order String -- Preserves Current Iteration Order
Given the wiki_config.metadata_display_order is "" (empty string, which is the default)
And an article has front matter with article_number, created, author, visibility
When prepare_metadata_context() builds the metadata panel
Then fields appear in current codebase order:
article_number first (if present), remaining fields in dict iteration order
And the result is identical to calling with wiki_config=None
And no custom sorting is appliedAC7: Duplicate Fields in Order -- Field Appears Only Once
Given the wiki_config.metadata_display_order is "created,author,created,modified"
And an article has front matter with created, author, modified
When prepare_metadata_context() builds the metadata panel
Then each field appears exactly once
And the order follows the first occurrence in the order string:
1. created
2. author
3. modifiedAC8: Nonexistent Fields in Order -- Silently Ignored
Given the wiki_config.metadata_display_order is "nonexistent_field,created,also_fake,modified"
And an article has front matter with created and modified
When prepare_metadata_context() builds the metadata panel
Then nonexistent_field and also_fake are silently ignored
And the panel shows:
1. created
2. modified
And no error or warning is logged for nonexistent fieldsAC9: Config Round-Trip
Given a WikiConfig with metadata_display_order set to "author,visibility,created"
When the config is serialized to config.json and loaded back
Then the metadata_display_order value is "author,visibility,created" exactly
And no data is lost or defaulted during the round-tripAC10: Config Web UI -- Display Order Text Input
Given an admin navigates to the Config Web UI "Wiki" section
When the page loads
Then a text input is visible for "Metadata Display Order"
And it is pre-populated with the current metadata_display_order value
And help text explains: "Comma-separated list of metadata field keys. Fields not listed appear after listed ones, sorted alphabetically."
When the admin changes the order and saves
Then the config.json is updated with the new metadata_display_order value
And the next wiki article view reflects the new field orderingAC11: Backward Compatibility -- wiki_config=None
Given a caller invokes prepare_metadata_context() without wiki_config (wiki_config=None)
When the metadata panel is built
Then the field ordering matches the current codebase behavior
And article_number appears first (if present)
And remaining fields appear in iteration order
And no error or exception is raisedAC12: Golden Regression -- Default Config Matches wiki_config=None
Given the wiki_config uses all default values (metadata_display_order = "")
And an article has front matter with article_number, publication_status, created, modified, author, visibility, views
When prepare_metadata_context() is called with default wiki_config
Then the output is identical (same fields, same order) to calling prepare_metadata_context() with wiki_config=None
And article_number is first, followed by remaining fields in dict iteration order
Note: This is trivially satisfied because empty order string short-circuits to current behaviorAC13: Interaction with real_views from Database
Given the wiki_config.metadata_display_order is "real_views,created,modified"
And an article has real_views tracked in the database (view count > 0)
And the article has created and modified in front matter
When prepare_metadata_context() builds the metadata panel
Then the fields appear in this order:
1. real_views (labeled "Views")
2. created (labeled "Created")
3. modified (labeled "Modified")Technical Implementation Details
Component Structure
src/code_indexer/server/utils/config_manager.py
- WikiConfig: add metadata_display_order field (comma-separated string, default "" = preserve current order)
src/code_indexer/server/wiki/wiki_service.py
- Update prepare_metadata_context() to:
1. Track metadata key alongside each tuple during construction
2. After building all tuples, sort according to wiki_config.metadata_display_order
3. Unlisted fields appended alphabetically
4. Return sorted list of 2-tuples (label, value)
src/code_indexer/server/web/templates/partials/config_section.html
- Add text input for metadata_display_order in Wiki section
- Include help text explaining the format
src/code_indexer/server/web/routes.py
- Handle metadata_display_order field in config save endpoint
Internal Data Structure During Ordering
To preserve the metadata key for ordering purposes while producing the final tuple output, prepare_metadata_context() internally uses a keyed intermediate structure:
@dataclass
class _MetadataItem:
key: str # e.g., "article_number", "created"
label: str # e.g., "Salesforce Article", "Created"
value: str # e.g., "KA-12345", "March 15, 2024"The final output strips the key, returning only (label, value) tuples.
Testing Requirements
Unit Test Coverage
- Default order (empty string): field ordering matches current codebase exactly (iteration order preserved)
- Custom order: "author,modified,created" reorders fields correctly
- Unlisted fields: appear after listed ones, sorted alphabetically by key
- Disabled field exclusion: article_number in order string but enable_article_number=False -- excluded
- Disabled field exclusion: publication_status in order string but enable_publication_status=False -- excluded
- Empty order string: preserves current iteration order (same as wiki_config=None)
- Duplicate fields: "created,author,created" -- each field appears once, first occurrence position
- Nonexistent fields: silently ignored, no error
- wiki_config=None: ordering matches current codebase (backward compat)
- Golden regression: default wiki_config (empty order) == wiki_config=None order
- real_views ordering: database-sourced field respects configured order
- Config round-trip: metadata_display_order survives JSON serialize/deserialize
Integration Test Coverage
- Config Web UI text input displays current metadata_display_order
- Saving new order via Web UI updates config.json
E2E Test Coverage
- Admin changes order to "author,created,modified", views article, verifies author appears first
- Admin sets empty order, views article, verifies current iteration order preserved
Definition of Done
Functional Completion
- All 13 acceptance criteria satisfied with evidence
- Configurable ordering works for all metadata fields including real_views from DB
- Disabled fields excluded regardless of order string presence
- Edge cases handled: empty string, duplicates, nonexistent fields
Quality Validation
- >90% test coverage for ordering-related code paths
- All tests passing (unit, integration, E2E)
- Code review approved
- Manual testing validated with evidence
- fast-automation.sh passes with zero failures
Integration Readiness
- Story delivers working, deployable software
- Full vertical slice: config field + service ordering logic + Web UI input
- No broken functionality
- Backward compatible: existing deployments see identical field ordering
Priority: LOW
Dependencies: Story 1 (WikiConfig dataclass and config injection pattern must exist)
Success Metric: Default order matches current behavior exactly; custom order reorders fields as specified; disabled fields excluded regardless of order string