Skip to content

WIP on unit names#136

Draft
mitch10593 wants to merge 1 commit intomainfrom
feature/135-add-units-names-full-text
Draft

WIP on unit names#136
mitch10593 wants to merge 1 commit intomainfrom
feature/135-add-units-names-full-text

Conversation

@mitch10593
Copy link
Contributor

@mitch10593 mitch10593 commented Mar 24, 2026

Summary by Sourcery

Add support for extracting and serving human-readable DCS unit display names and exposing them in the map UI, with a CLI entry point and startup integration.

New Features:

  • Introduce a CLI application with commands to run the server and extract DCS unit display names into a JSON mapping.
  • Add unit display name extraction from DCS Lua files and JSON-backed lookup for use at runtime.
  • Expose unit display names via the map data API and render them as tooltips in the zone modal UI.

Enhancements:

  • Integrate startup lifespan hook to configure logging and refresh unit display names based on configured DCS install path.
  • Extend configuration to include an optional DCS installation path used for unit name extraction.

Documentation:

  • Document optional configuration and CLI usage for generating unit display names in the README.

Tests:

  • Add unit tests covering loading of the unit display names mapping from disk.

@mitch10593 mitch10593 self-assigned this Mar 24, 2026
@mitch10593 mitch10593 linked an issue Mar 24, 2026 that may be closed by this pull request
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 24, 2026

Reviewer's Guide

Adds a full unit display-name extraction and lookup pipeline (CLI, startup integration, API wiring, and frontend usage) so that DCS unit type codes can be shown with human-readable names, plus minor logging and config extensions.

Sequence diagram for unit display name extraction at server startup

sequenceDiagram
    participant FastAPIApp as FastAPI_app
    participant Lifespan as lifespan
    participant Config as get_config
    participant UnitNames as unit_names
    participant FS as FileSystem

    FastAPIApp->>Lifespan: start (lifespan hook)
    Lifespan->>Lifespan: _configure_logging()
    Lifespan->>Config: get_config()
    Config-->>Lifespan: Config(dcs.install_path)
    Lifespan->>FS: check Path(dcs.install_path).exists()
    alt install_path exists
        Lifespan->>UnitNames: refresh_unit_display_names(dcs_install)
        UnitNames->>UnitNames: extract_all(dcs_install)
        UnitNames->>FS: glob Lua files
        FS-->>UnitNames: Lua file paths
        loop for each Lua file
            UnitNames->>UnitNames: extract_from_file(lua_file)
        end
        UnitNames->>UnitNames: save_unit_display_names(mappings)
        UnitNames->>FS: write var/unit_display_names.json
        UnitNames-->>Lifespan: count
        Lifespan->>UnitNames: get_unit_display_names()
        UnitNames-->>Lifespan: mapping
        Lifespan->>UnitNames: get_unit_display_names.cache_clear()
    else install_path configured but missing
        Lifespan->>Lifespan: log warning
    else install_path not configured
        Lifespan->>FS: check UNIT_NAMES_PATH.exists()
        alt unit names file exists
            Lifespan->>UnitNames: get_unit_display_names()
            UnitNames-->>Lifespan: mapping
        else no file
            Lifespan->>Lifespan: log info (codes will be shown as-is)
        end
    end
    Lifespan-->>FastAPIApp: startup complete
    FastAPIApp-->>Lifespan: shutdown
    Lifespan-->>FastAPIApp: lifespan exit
Loading

Sequence diagram for map data request and unit display name usage

sequenceDiagram
    actor User as Browser_user
    participant Browser as Browser_JS
    participant API as FastAPI_foothold_get_map_data
    participant UnitNames as unit_names

    User->>Browser: Open map page
    Browser->>API: GET /api/map_data
    API->>API: build sitac data
    API->>API: collect all_unit_types from zones
    API->>UnitNames: get_unit_display_names()
    UnitNames-->>API: full_mapping{type_lower:display_name}
    API->>API: unit_display_names = filtered mapping
    API-->>Browser: MapData(unit_display_names,…)
    Browser->>Browser: unitDisplayNames = data.unit_display_names
    User->>Browser: Open zone modal
    Browser->>Browser: openZoneModal(zone)
    Browser->>Browser: for each group.units
    Browser->>Browser: lookup unitDisplayNames[unitType]
    Browser->>Browser: render <span title=displayName>unitType xN</span>
    User->>Browser: Hover unit type
    Browser-->>User: Show human readable tooltip
Loading

Updated class diagram for unit names pipeline and config

classDiagram
    class DcsConfig {
        str saved_games
        str~None install_path
    }

    class MapData {
        dict~str,str~ unit_display_names
    }

    class UnitNamesModule {
        +Path UNIT_NAMES_PATH
        +dict~str,str~ extract_from_file(filepath: Path)
        +dict~str,str~ extract_all(dcs_path: Path)
        +void save_unit_display_names(mappings: dict~str,str~, output: Path)
        +int refresh_unit_display_names(dcs_path: Path)
        +dict~str,str~ get_unit_display_names()
    }

    class ConsoleApp {
        +serve()
        +extract_unit_names(dcs_path: str~None, output: Path~None)
    }

    class FastAPIMain {
        +lifespan(application: FastAPI)
        +_configure_logging()
    }

    class ConfigModule {
        +get_config()
    }

    ConsoleApp ..> ConfigModule : uses get_config
    ConsoleApp ..> UnitNamesModule : uses extract_all, save_unit_display_names, UNIT_NAMES_PATH
    FastAPIMain ..> ConfigModule : uses get_config
    FastAPIMain ..> UnitNamesModule : uses refresh_unit_display_names, get_unit_display_names, UNIT_NAMES_PATH
    MapData ..> UnitNamesModule : uses get_unit_display_names
    DcsConfig <.. ConfigModule : contained in Config
Loading

File-Level Changes

Change Details Files
Introduce unit display-name extraction/lookup module and CLI integration.
  • Add unit_names.py with helpers to scan DCS Lua files, extract type->DisplayName mappings, save them to JSON, and provide a cached loader for runtime use
  • Add console.py Typer-based CLI with serve and extract-unit-names commands, including validation of DCS path and JSON output destination
  • Register foothold-sitac console script in pyproject.toml and add typer dependency
  • Extend DcsConfig with optional install_path and add tests for get_unit_display_names behavior when the JSON file exists or is missing
src/foothold_sitac/unit_names.py
src/foothold_sitac/console.py
src/foothold_sitac/config.py
src/foothold_sitac/__init__.py
pyproject.toml
tests/units/test_unit_names.py
Wire unit display names into app startup and API responses, and surface them in the frontend map UI.
  • Add FastAPI lifespan handler in main.py to configure logging and, when dcs.install_path is set, auto-refresh unit_display_names.json at startup, falling back gracefully when unavailable
  • Extend MapData schema and API handler to compute a minimal unit_display_names mapping for the current sitac and include it in /map-data responses
  • Update frontend map.js to receive unit_display_names from the API and render unit codes wrapped in spans with title tooltips showing the display names
  • Document the unit-name feature and CLI usage in README, including config and example commands
src/foothold_sitac/main.py
src/foothold_sitac/foothold_api_router.py
src/foothold_sitac/schemas.py
src/foothold_sitac/static/js/map.js
README.md

Assessment against linked issues

Issue Objective Addressed Explanation
#135 Provide a system that maps DCS internal unit type codes to human-readable full-text names and use these names in the web UI for units in groups.
#135 Implement automated extraction of unit type-to-full-text-name mappings from the DCS unit database (including MUD spikes) using the DCS installation, configurable via application settings.
#135 Add support for displaying thumbnail images for units in the UI to give a visual representation of unit types. The PR only introduces name extraction, storage, API exposure, and UI tooltips for unit display names; it does not add any image/thumbnail fields, assets, or frontend rendering for unit thumbnails.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@mitch10593 mitch10593 added this to the 0.4 milestone Mar 24, 2026
@mitch10593 mitch10593 marked this pull request as draft March 24, 2026 19:47
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/foothold_sitac/main.py" line_range="37-45" />
<code_context>
+    config = get_config()
+    dcs_install = config.dcs.install_path
+
+    if dcs_install and Path(dcs_install).exists():
+        logger.info("DCS install path configured: %s", dcs_install)
+        count = refresh_unit_display_names(Path(dcs_install))
+        if count:
+            logger.info("Refreshed %d unit display names at startup", count)
+            get_unit_display_names.cache_clear()
</code_context>
<issue_to_address>
**suggestion (performance):** Full unit-name extraction on every startup may be very slow for large DCS installs.

Calling `refresh_unit_display_names` on every startup will repeatedly scan a large portion of the DCS install tree (potentially thousands of Lua files), which can noticeably slow startup or cause timeouts in constrained environments. Consider limiting this to cases where the JSON file is missing, making it configurable, or moving the heavy extraction to an explicit CLI-only command while startup only loads the existing JSON file.

```suggestion
    if dcs_install and Path(dcs_install).exists():
        logger.info("DCS install path configured: %s", dcs_install)
        if UNIT_NAMES_PATH.exists():
            names = get_unit_display_names()
            logger.info("Using existing unit display names file (%d entries)", len(names))
        else:
            count = refresh_unit_display_names(Path(dcs_install))
            if count:
                logger.info("Refreshed %d unit display names at startup", count)
                get_unit_display_names.cache_clear()
            else:
                logger.warning("No unit mappings extracted from %s", dcs_install)
    elif dcs_install:
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +37 to +45
if dcs_install and Path(dcs_install).exists():
logger.info("DCS install path configured: %s", dcs_install)
count = refresh_unit_display_names(Path(dcs_install))
if count:
logger.info("Refreshed %d unit display names at startup", count)
get_unit_display_names.cache_clear()
else:
logger.warning("No unit mappings extracted from %s", dcs_install)
elif dcs_install:
Copy link

Choose a reason for hiding this comment

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

suggestion (performance): Full unit-name extraction on every startup may be very slow for large DCS installs.

Calling refresh_unit_display_names on every startup will repeatedly scan a large portion of the DCS install tree (potentially thousands of Lua files), which can noticeably slow startup or cause timeouts in constrained environments. Consider limiting this to cases where the JSON file is missing, making it configurable, or moving the heavy extraction to an explicit CLI-only command while startup only loads the existing JSON file.

Suggested change
if dcs_install and Path(dcs_install).exists():
logger.info("DCS install path configured: %s", dcs_install)
count = refresh_unit_display_names(Path(dcs_install))
if count:
logger.info("Refreshed %d unit display names at startup", count)
get_unit_display_names.cache_clear()
else:
logger.warning("No unit mappings extracted from %s", dcs_install)
elif dcs_install:
if dcs_install and Path(dcs_install).exists():
logger.info("DCS install path configured: %s", dcs_install)
if UNIT_NAMES_PATH.exists():
names = get_unit_display_names()
logger.info("Using existing unit display names file (%d entries)", len(names))
else:
count = refresh_unit_display_names(Path(dcs_install))
if count:
logger.info("Refreshed %d unit display names at startup", count)
get_unit_display_names.cache_clear()
else:
logger.warning("No unit mappings extracted from %s", dcs_install)
elif dcs_install:

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add units names "full text"

1 participant