Gate endpoint UI refresh on fresh telemetry and land endpoint agent

A command reaching 'succeeded' only proves the agent ran the action, not that it posted a new telemetry snapshot. Reloading panels on command success alone re-rendered stale service/process rows, so a stopped process could still show running right after Refresh Status.

Add a lightweight telemetrymeta probe exposing lastreportedat and gate both the header Refresh Status action and inline row Start/Stop on that stamp advancing past a pre-action baseline. Polling is bounded so an offline or idle agent never hangs the button, and messaging distinguishes a confirmed refresh from a queued one.

Bring the .NET endpoint agent source (service, tray, installer) into the repo so Cameron can merge and test, with an agent/.gitignore keeping bin/obj/publish out. Includes the DncMain launch-path fix, tray single-file host env scrub, and best-effort file logger.
This commit is contained in:
benjamin.baker
2026-08-28 15:07:20 -04:00
parent c001657582
commit af133372b4
46 changed files with 4593 additions and 128 deletions

View File

@@ -260,10 +260,12 @@ _COLLECTOR_SCRIPT = os.path.join(
def _embed_store_path(script_text, path):
"""Return the collector script with $NetworkStoreRoot set to path.
The script ships with a site-specific default on that line; rewriting it
means an operator downloads a script already pointed at this facility's CSV
store and does not have to edit PowerShell by hand. A blank path leaves the
shipped default untouched.
The script ships with a BLANK default on that line; rewriting it means an
operator downloads a script already pointed at this facility's CSV store and
does not have to edit PowerShell by hand. A blank path leaves the shipped
blank default untouched, so a site that has not configured
asset_import_csv_location keeps everything local instead of inheriting
another facility's share.
"""
if not path:
return script_text
@@ -281,7 +283,6 @@ def _embed_store_path(script_text, path):
@settings_bp.route('/asset-import/script', methods=['GET'])
@jwt_required()
@require_role('admin')
def download_collector_script():
"""Download Collect-ShopDB.ps1 with this site's CSV path embedded."""
@@ -300,7 +301,6 @@ def download_collector_script():
@settings_bp.route('/asset-import/templates', methods=['GET'])
@jwt_required()
@require_role('admin')
def list_import_templates():
"""List the importable CSV tables in the order they must be uploaded."""
@@ -312,7 +312,6 @@ def list_import_templates():
@settings_bp.route('/asset-import/templates/<tablename>', methods=['GET'])
@jwt_required()
@require_role('admin')
def download_import_template(tablename):
"""Download a generated CSV template for a single importable table."""
@@ -356,7 +355,6 @@ def _existing_hostname_map():
@settings_bp.route('/asset-import/import', methods=['POST'])
@jwt_required()
@require_role('admin')
def import_asset_csvs():
"""Validate uploaded CSVs and, when commit=true, load them.