feat: pluggable workspace registry system - #84
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…controls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd bar to log view Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…angelog Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…performance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…leanup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduce end-to-end Microsoft Graph integration to resolve Intune app GUIDs. Backend: new src-tauri/src/graph_api.rs implements WAM-based Windows auth, token caching, batch/single Graph requests, paginated app fetches and an in-memory GUID cache; adds fetch_all_apps and resolve_guids utilities. Frontend: new GraphApiTab settings UI to enable/sign-in/pre-populate cache, a startup hook to auto-connect and populate cache, status bar indicator for Graph status, and enhancements to the GUID registry dialog (tabs, filtering, publisher/type columns). Add lib/graph-registry.ts to convert GraphAppInfo to GuidRegistry entries and update types (GuidCategory, publisher). Also improve event_tracker to extract PolicyId from JSON payloads. Wire startup import in main.tsx and add ui-store state/handlers for graphApiEnabled and graphApiStatus.
Add opt-in Graph API support to resolve Intune app GUIDs to display names using the device's existing Entra ID session via WAM (Web Account Manager). No app registration required — uses the Microsoft Graph PowerShell public client ID. - WAM authentication with HWND interop for Win32 desktop apps - Graph API client with batch resolution ($batch endpoint, 20 per request) - Pre-populate cache button fetches all tenant apps in one call - GraphApi source variant (highest confidence) in GuidRegistry - Settings tab with opt-in toggle (off by default), consent warnings, and connection status display - Automatic enrichment during Intune log analysis when enabled Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix analyze_intune_logs to use app.state() instead of cfg-gated parameter (Tauri generate_handler! can't handle #[cfg] on parameters) - Gate Manager import to windows-only in both lib.rs and intune.rs - Resolve merge conflicts in ui-store.ts (recentSessions + graphApi state) - Resolve merge conflicts in GraphApiTab.tsx (keep buildGraphRegistryEntries) - Fix GuidRegistryDialog aria-label to use entry.guid Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tion refresh, diff close Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Resolve lib.rs conflict (keep both Graph API + Sysmon commands) - Add verbose Sysmon workspace entry to changelog Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6 tasks: shim definitions, AppShell/FileSidebar/ui-store/Toolbar refactors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates shim WorkspaceDefinition objects for the 7 remaining workspaces (log, intune, new-intune, dsregcmd, macos-diag, deployment, event-log), exports LogSidebar/IntuneSidebar/DsregcmdSidebar from FileSidebar.tsx, and registers all 8 workspaces in the workspace registry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the 8-way if/else chain in renderWorkspace() with a registry lookup + Suspense for all non-log workspaces. Log workspace inline rendering (DiffView, RegistryViewer, folder overlay, InfoPane) is preserved as a special case. TabStrip and FindBar conditionals now consult workspace capabilities flags instead of hard-coding activeView. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the ternary chain (isIntuneWorkspace / activeView === 'sysmon' checks) with a registry lookup via getWorkspace(activeView).sidebar, and drive the footer bar from capabilities.footerBar. Remove now-unused SysmonSidebar direct import and isIntuneWorkspace import. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove WORKSPACE_PLATFORM_MAP constant and inline filter logic from getAvailableWorkspaces(). Delegate to getRegistryWorkspaces() from the workspace registry instead, mapping WorkspaceDefinition[] back to WorkspaceId[] to preserve the existing public API surface. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace WORKSPACE_LABELS, getOpenFileDialogFilters(), and getOpenActionLabels() with direct lookups from getWorkspace() in the workspace registry, eliminating ~75 lines of duplicated metadata. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move all dsregcmd-specific files into src/workspaces/dsregcmd/ to make the workspace fully self-contained, following the same pattern as sysmon. - git mv types/dsregcmd.ts → workspaces/dsregcmd/types.ts - git mv stores/dsregcmd-store.ts → workspaces/dsregcmd/dsregcmd-store.ts - git mv components/dsregcmd/* → workspaces/dsregcmd/ (7 files) - Extract DsregcmdSidebar from FileSidebar.tsx into workspaces/dsregcmd/DsregcmdSidebar.tsx - Update index.ts shim to use local ./ imports - Update all external importers (Toolbar, StatusBar, EvidenceBundleDialog, commands.ts, dsregcmd-source.ts, dsregcmd-store.test.ts, event-log/index.ts) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move types, store, and all 7 components out of src/types/, src/stores/, and src/components/event-log-workspace/ into the unified workspace directory. Update all internal imports to use relative paths within the workspace. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move types, store, and all 9 components from their scattered locations (src/types/, src/stores/, src/components/macos-diag/) into the unified workspace directory src/workspaces/macos-diag/. Update all internal and external import paths accordingly. TypeScript passes clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves deployment-store.ts and all 3 component files (DeploymentWorkspace, DeploymentErrorCard, DeploymentSuccessTable) from their legacy locations into src/workspaces/deployment/. Updates all import paths in the moved files, the workspace index shim, StatusBar.tsx, and both dynamic imports in Toolbar.tsx. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves all 19 intune components, the intune store (1,095 lines), types, hook, and test file from their scattered locations into the consolidated src/workspaces/intune/ directory. Extracts IntuneSidebar from FileSidebar.tsx into its own file with helpers inlined. Updates all importers across layout, dialogs, hooks, and lib modules. Both the intune and new-intune workspace shims now reference local workspace paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…getBaseName - Create src/components/common/sidebar-primitives.tsx with SourceSummaryCard, SourceStatusNotice, SectionHeader, EmptyState, and SidebarActionButton - Remove inline copies of all five components from FileSidebar, IntuneSidebar, DsregcmdSidebar, and SysmonSidebar; import from shared module instead - Widen canonical getBaseName signature to string | null | undefined - Remove exported getBaseName from log-store; import from file-paths instead - Update all callers in log-source, dsregcmd-source, EvidenceBundleDialog, StatusBar, IntuneSidebar, SysmonSidebar, and FileSidebar to use file-paths - Also removes local getDirectoryName copy from EvidenceBundleDialog Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…stry lookup Add statusLabel to WorkspaceDefinition; set overrides on log, intune, and new-intune workspaces. getUiChromeStatus now resolves labels via getWorkspace() and branches only on capabilities.detailsPane, eliminating the 8-way if/else. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mmandState Move workspace-specific analysis logic (intune, dsregcmd, sysmon, deployment) from Toolbar.tsx into each workspace's onOpenSource in its definition. Replace the openSourceForWorkspace if/else chain with a registry lookup. Add knownSources and tailing to WorkspaceCapabilities and use them in commandState instead of hardcoded workspace ID checks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a centralized, typed workspace registry (WorkspaceDefinition + registry map) and migrates multiple workspaces to self-contained folders under src/workspaces/, replacing scattered workspace-specific branching across the UI. It also includes several adjacent feature additions/refactors (workspace-specific sidebars, Graph API integration hooks/commands, session save/restore, and log merge/diff utilities/UI) that touch both the frontend and Tauri backend.
Changes:
- Added a pluggable workspace registry (
src/workspaces/types.ts,src/workspaces/registry.ts) and migrated workspaces (log/intune/new-intune/dsregcmd/macos-diag/deployment/event-log/sysmon) to the new structure. - Introduced shared sidebar primitives and new workspace-specific sidebars (e.g., Intune/Dsregcmd/Sysmon).
- Added supporting features/utilities across the app: Graph API integration plumbing, session save/restore file format + commands, and merge/diff helpers and UI components.
Reviewed changes
Copilot reviewed 142 out of 155 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/workspaces/types.ts | Adds core WorkspaceDefinition and capability/filter/action-label typing. |
| src/workspaces/registry.ts | Central registry + platform/enabled filtering helpers. |
| src/workspaces/log/index.ts | Registers Log Explorer workspace definition + capabilities/filters. |
| src/workspaces/intune/index.ts | Registers Intune workspace + shared createIntuneOnOpenSource handler (incl. Graph toggle). |
| src/workspaces/new-intune/index.ts | Registers “new-intune” workspace pointing at Intune components/handlers. |
| src/workspaces/intune/types.ts | Moves/extends Intune workspace types (GUID registry GraphApi source + metadata). |
| src/workspaces/intune/intune-store.ts | Migrates Intune store into workspace folder; adds mergeGuidRegistry. |
| src/workspaces/intune/intune-store.test.ts | Adds Intune store unit tests (Vitest). |
| src/workspaces/intune/use-intune-analysis-progress.ts | Updates imports to new workspace-local store/types. |
| src/workspaces/intune/useTimeWindowFilter.ts | Updates imports to new workspace-local store/types. |
| src/workspaces/intune/SummaryView.tsx | Updates imports to new workspace-local store/types. |
| src/workspaces/intune/SummaryViewComponents.tsx | Updates imports to new workspace-local types. |
| src/workspaces/intune/summary-view-logic.ts | Updates imports to new workspace-local types. |
| src/workspaces/intune/OverviewSurface.tsx | Updates store import location for event-log ID lookup. |
| src/workspaces/intune/NewIntuneWorkspace.tsx | Updates toolbar hook import path + store import. |
| src/workspaces/intune/InvestigationPanel.tsx | Updates imports to new workspace-local types. |
| src/workspaces/intune/IntuneDashboard.tsx | Updates store import location. |
| src/workspaces/intune/IntuneDashboardHeader.tsx | Updates toolbar hook import path + store import. |
| src/workspaces/intune/IntuneDashboardNavBar.tsx | Updates store/types imports to workspace-local paths. |
| src/workspaces/intune/IntuneSidebar.tsx | Adds new Intune workspace sidebar built on shared primitives. |
| src/workspaces/intune/EventTimeline.tsx | Updates store/types imports to workspace-local paths. |
| src/workspaces/intune/EventTimelineRow.tsx | Updates types import to workspace-local types. |
| src/workspaces/intune/EventTimelineRow.test.tsx | Updates types import to workspace-local types. |
| src/workspaces/intune/EventActivityView.tsx | Updates store/types imports; improves GUID lookup fallback behavior. |
| src/workspaces/intune/DownloadSurface.tsx | Updates types import to workspace-local types. |
| src/workspaces/intune/DownloadStats.tsx | Updates store/types imports to workspace-local paths. |
| src/workspaces/intune/EventLogSurface.tsx | Updates store import location to workspace-local store. |
| src/workspaces/intune/intune-dashboard-utils.ts | Updates types import; switches non-nullable type import target to workspace-local types. |
| src/workspaces/sysmon/index.ts | Registers Sysmon workspace definition + lazy component/sidebar + open handler. |
| src/workspaces/sysmon/types.ts | Adds Sysmon workspace-local types (events/summary/dashboard/config). |
| src/workspaces/sysmon/sysmon-store.ts | Updates Sysmon store types import to workspace-local types. |
| src/workspaces/sysmon/use-sysmon-analysis-progress.ts | Updates import path to workspace-local sysmon-store. |
| src/workspaces/sysmon/SysmonWorkspace.tsx | Updates store import path + toolbar hook import path. |
| src/workspaces/sysmon/SysmonEventTable.tsx | Updates store/types import paths to workspace-local types. |
| src/workspaces/sysmon/SysmonDashboardView.tsx | Updates store import path to workspace-local sysmon-store. |
| src/workspaces/sysmon/SysmonSummaryView.tsx | Updates store import path to workspace-local sysmon-store. |
| src/workspaces/sysmon/SysmonConfigView.tsx | Updates store import path to workspace-local sysmon-store. |
| src/workspaces/sysmon/SysmonSidebar.tsx | Adds Sysmon-specific sidebar using shared primitives. |
| src/workspaces/sysmon/DashboardMetricCards.tsx | Updates Sysmon types import to workspace-local types. |
| src/workspaces/sysmon/DashboardEventTypeChart.tsx | Updates Sysmon types import to workspace-local types. |
| src/workspaces/sysmon/DashboardTimeline.tsx | Updates Sysmon types import to workspace-local types. |
| src/workspaces/sysmon/DashboardSecurityAlerts.tsx | Updates Sysmon types import to workspace-local types. |
| src/workspaces/sysmon/DashboardTopList.tsx | Updates Sysmon types import to workspace-local types. |
| src/workspaces/macos-diag/index.ts | Registers macOS diagnostics workspace definition. |
| src/workspaces/macos-diag/types.ts | Adds macOS diagnostics workspace-local types. |
| src/workspaces/macos-diag/macos-diag-store.ts | Updates types import to workspace-local types. |
| src/workspaces/macos-diag/MacosDiagWorkspace.tsx | Updates store import path to workspace-local store. |
| src/workspaces/macos-diag/MacosDiagUnifiedLogTab.tsx | Updates store import path to workspace-local store. |
| src/workspaces/macos-diag/MacosDiagTabStrip.tsx | Updates store/types import paths to workspace-local paths. |
| src/workspaces/macos-diag/MacosDiagProfilesTab.tsx | Updates store import path to workspace-local store. |
| src/workspaces/macos-diag/MacosDiagPackagesTab.tsx | Updates store import path to workspace-local store. |
| src/workspaces/macos-diag/MacosDiagIntuneLogsTab.tsx | Updates store/types import paths to workspace-local paths. |
| src/workspaces/macos-diag/MacosDiagEnvironmentBanner.tsx | Updates types import to workspace-local types. |
| src/workspaces/macos-diag/MacosDiagDefenderTab.tsx | Updates store/types import paths to workspace-local paths. |
| src/workspaces/macos-diag/MacosDiagFdaGuide.tsx | Adds FDA guidance UI (invokes backend command to open settings if available). |
| src/workspaces/dsregcmd/index.ts | Registers dsregcmd workspace definition + onOpenSource behavior. |
| src/workspaces/dsregcmd/types.ts | Adjusts EventLogAnalysis type reference to shared src/types/event-log. |
| src/workspaces/dsregcmd/dsregcmd-store.ts | Moves dsregcmd store under workspace; updates type imports. |
| src/workspaces/dsregcmd/DsregcmdWorkspace.tsx | Updates store import path + toolbar hook import path. |
| src/workspaces/dsregcmd/DsregcmdEventLogSurface.tsx | Updates store import path to workspace-local dsregcmd-store. |
| src/workspaces/dsregcmd/dsregcmd-formatters.ts | Updates types import to workspace-local dsregcmd types. |
| src/workspaces/dsregcmd/fact-group-builders.ts | Updates types import to workspace-local dsregcmd types. |
| src/workspaces/dsregcmd/DiagnosticInsightsCard.tsx | Updates types import to workspace-local dsregcmd types. |
| src/workspaces/dsregcmd/PolicyEvidencePane.tsx | Adds UI primitives for dsregcmd evidence/policy rendering. |
| src/workspaces/dsregcmd/FactGroupRenderer.tsx | Adds table renderer for dsregcmd fact groups. |
| src/workspaces/dsregcmd/DsregcmdSidebar.tsx | Adds dsregcmd-specific sidebar using shared primitives. |
| src/workspaces/deployment/index.ts | Registers deployment workspace definition + open handler. |
| src/workspaces/deployment/deployment-store.ts | Adds deployment analysis store + backend invoke plumbing. |
| src/workspaces/deployment/DeploymentWorkspace.tsx | Updates store import path to workspace-local deployment-store. |
| src/workspaces/deployment/DeploymentErrorCard.tsx | Updates store import path to workspace-local deployment-store. |
| src/workspaces/deployment/DeploymentSuccessTable.tsx | Updates store import path to workspace-local deployment-store. |
| src/workspaces/event-log/index.ts | Registers event-log workspace definition (currently miswired sidebar/filters). |
| src/workspaces/event-log/types.ts | Extends EVTX parse result type to include errorMessages. |
| src/workspaces/event-log/SourcePicker.tsx | Updates store import path to workspace-local evtx-store. |
| src/workspaces/event-log/EvtxTimeline.tsx | Adds keyboard navigation + focusable listbox container; adjusts styles. |
| src/workspaces/event-log/EvtxTimelineRow.tsx | Updates types import to workspace-local event-log types. |
| src/workspaces/event-log/EvtxFilterBar.tsx | Updates store/types imports to workspace-local event-log files. |
| src/workspaces/event-log/EvtxDetailPane.tsx | Updates store import path; adjusts message panel sizing. |
| src/workspaces/event-log/EventLogWorkspace.tsx | Adds updated event-log workspace layout with resizable detail pane + progress bar. |
| src/workspaces/event-log/evtx-store.ts | Adds/relocates EVTX Zustand store; adds progress listener (currently module-scoped). |
| src/types/event-log.ts | Changes IntuneTimestampBounds import target to workspace Intune types. |
| src/stores/ui-store.ts | Replaces workspace platform map with registry lookups; adds new UI flags/persisted fields. |
| src/stores/evtx-store.ts | Removes old top-level EVTX store (moved under workspace). |
| src/stores/dsregcmd-store.test.ts | Updates dsregcmd-store test import path to workspace-local store. |
| src/main.tsx | Imports Graph API startup module. |
| src/hooks/use-graph-api-startup.ts | Adds persist-hydration-triggered Graph auto-connect + GUID registry merge. |
| src/hooks/use-app-menu.ts | Adds menu actions for session save/open. |
| src/lib/commands.ts | Updates types import targets; adds Graph API commands + graphApiEnabled option for Intune analysis. |
| src/lib/graph-registry.ts | Adds helper to convert Graph app info into GUID registry entries. |
| src/lib/session.ts | Defines session file format + validation/sanitization. |
| src/lib/session-save.ts | Implements session save flow (hash via backend, persist recent sessions). |
| src/lib/session-restore.ts | Implements session restore flow + integrity checks + state restoration. |
| src/lib/merge-entries.ts | Adds merge helpers (color assignment, merge, correlation helpers). |
| src/lib/diff-entries.ts | Adds diff normalization/classification helpers. |
| src/lib/log-source.ts | Removes local getBaseName helper; uses shared file-paths export. |
| src/lib/file-paths.ts | Broadens getBaseName input type to allow undefined. |
| src/lib/dsregcmd-source.ts | Moves dsregcmd type/store imports; uses shared getBaseName. |
| src/lib/profile-utils.ts | Updates macOS profile type import to workspace-local types. |
| src/lib/intune-sort.ts | Updates imports for Intune types/store to workspace-local paths. |
| src/components/common/sidebar-primitives.tsx | Adds shared sidebar primitive components for workspace sidebars. |
| src/components/dialogs/SettingsDialog.tsx | Adds Graph API settings tab (Windows-only). |
| src/components/dialogs/MergeTabsDialog.tsx | Adds UI for selecting tabs to merge into unified timeline. |
| src/components/dialogs/DiffConfigDialog.tsx | Adds UI for selecting two tabs to compare. |
| src/components/dialogs/EvidenceBundleDialog.tsx | Updates store imports; replaces local path helpers with shared file-paths utilities. |
| src/components/log-view/MergeLegendBar.tsx | Adds legend/toggles for merged timeline mode. |
| src/components/log-view/DiffHeader.tsx | Adds diff mode header with stats + display toggle + close action. |
| src/components/log-view/LogRow.tsx | Adds merge stripe + correlation highlight styling inputs. |
| src/components/log-view/LogListView.tsx | Integrates MergeLegendBar and correlated highlighting in merged mode. |
| src/components/log-view/InfoPane.tsx | Adds correlated-entries section for merged mode; uses fileBaseName helper. |
| src/components/log-view/AppWorkloadScriptDetail.tsx | Fixes UTF-8 base64 decode; tightens GetPolicies parsing types. |
| src/components/layout/TabStrip.tsx | Adds merged/diff close behavior + merged-tab labeling. |
| src/components/layout/StatusBar.tsx | Adds Graph API status indicator + EVTX status summary + tiny spinner. |
| src/components/event-log-workspace/EventLogWorkspace.tsx | Removes old event-log workspace component (moved to workspace folder). |
| src/components/event-log-workspace/ChannelPicker.tsx | Removes old channel picker (moved to workspace folder). |
| src-tauri/src/menu.rs | Adds File menu entries for session save/open + emits corresponding menu actions. |
| src-tauri/src/lib.rs | Registers new commands (file hash, Graph API); gates sysmon module on feature. |
| src-tauri/src/commands/mod.rs | Adds Graph API command module (Windows-only) and gates sysmon commands on feature. |
| src-tauri/src/commands/file_ops.rs | Adds compute_file_hash command (SHA-256 + size). |
| src-tauri/src/commands/intune.rs | Adds Graph API prefetch/enrichment path + policy metadata key normalization. |
| src-tauri/src/commands/graph_api.rs | Adds Tauri command wrappers for Graph API auth/resolve/fetch. |
| src-tauri/src/intune/guid_registry.rs | Adds GraphApi source + insert/unresolved helpers. |
| src-tauri/src/intune/event_tracker.rs | Tweaks appworkload event detail + adds PolicyId GUID extraction path + context scan fix. |
| src-tauri/src/intune/timeline.rs | Updates tests for new IntuneEvent fields. |
| src-tauri/src/event_log/models.rs | Adds error_messages to EVTX parse result model. |
| src-tauri/src/event_log/parser.rs | Initializes error_messages in parse result. |
| src-tauri/src/event_log/commands.rs | Adds per-channel progress emits and error message collection; includes channels with 0 events on errors. |
| src-tauri/Cargo.toml | Adds sysmon feature + sha2 dependency; adjusts feature wiring. |
| src-tauri/Cargo.lock | Adds sha2 dependency entry. |
| scripts/Launch-CMTraceOpen.sh | Fixes script root derivation for environments without BASH_SOURCE. |
| docs/superpowers/specs/2026-04-02-unified-timeline-design.md | Adds design spec for unified timeline merge/correlation. |
| docs/superpowers/specs/2026-04-02-session-save-restore-design.md | Adds design spec for session save/restore. |
| docs/superpowers/specs/2026-04-02-log-diff-design.md | Adds design spec for log diff. |
| CHANGELOG.md | Updates unreleased notes (currently very broad scope under PR #82). |
| .gitignore | Ignores brainstorming + Claude local settings artifacts. |
| .github/workflows/cmtrace-ci.yml | Adds explicit workflow permissions. |
| .claude/settings.local.json | Removes committed Claude local settings file. |
Comments suppressed due to low confidence (1)
src/workspaces/event-log/EvtxTimeline.tsx:208
- The focusable listbox explicitly sets
outline: "none", which removes the visible focus indicator for keyboard users. Keep the default outline, or replace it with an accessible custom focus style (e.g., using:focus-visiblestyling) so focus remains apparent when navigating with arrow keys.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| sidebar: lazy(() => | ||
| import("../dsregcmd/DsregcmdSidebar").then((m) => ({ | ||
| default: m.DsregcmdSidebar, | ||
| })) | ||
| ), |
There was a problem hiding this comment.
The Event Log workspace is wired to lazily load the dsregcmd sidebar, which looks like an accidental copy/paste and will render the wrong sidebar UI when activeView === "event-log". Replace this with an Event Log-specific sidebar component (if needed), or omit sidebar so FileSidebar falls back appropriately.
| fileFilters: [ | ||
| { name: "Log Files", extensions: ["log"] }, | ||
| { name: "Old Log Files", extensions: ["lo_"] }, | ||
| { name: "Registry Files", extensions: ["reg"] }, | ||
| { name: "All Files", extensions: ["*"] }, | ||
| ], | ||
| actionLabels: { | ||
| file: "Open File", | ||
| folder: "Open Folder", | ||
| placeholder: "Open...", | ||
| }, |
There was a problem hiding this comment.
fileFilters/actionLabels for the Event Log workspace are set up for .log/.reg files, but this workspace’s SourcePicker and backend commands are EVTX-focused. This will cause the global Open dialog to show incorrect filters/labels when the Event Log workspace is active. Align these with EVTX (e.g., .evtx) and appropriate button text.
| fileFilters: [ | ||
| { name: "Log Files", extensions: ["log"] }, | ||
| { name: "Old Log Files", extensions: ["lo_"] }, | ||
| { name: "Registry Files", extensions: ["reg"] }, | ||
| { name: "All Files", extensions: ["*"] }, | ||
| ], | ||
| actionLabels: { | ||
| file: "Open File", | ||
| folder: "Open Folder", | ||
| placeholder: "Open...", | ||
| }, | ||
| onOpenSource: async (source, _trigger) => { | ||
| const folderPath = | ||
| source.kind === "folder" | ||
| ? source.path | ||
| : source.kind === "known" | ||
| ? source.defaultPath | ||
| : null; | ||
| if (folderPath) { | ||
| const { useDeploymentStore } = await import("./deployment-store"); | ||
| await useDeploymentStore.getState().analyzeFolder(folderPath); | ||
| } |
There was a problem hiding this comment.
onOpenSource ignores source.kind === "file", but this workspace advertises file filters and an "Open File" action label. That yields a no-op when a user opens a file. Either handle file sources (e.g., analyze the file’s parent folder / treat a file as a single-file folder analysis) or remove the file open affordance for this workspace.
| import type { IntuneTimestampBounds } from "../workspaces/intune/types"; | ||
|
|
There was a problem hiding this comment.
src/types/event-log.ts now type-imports IntuneTimestampBounds from src/workspaces/intune/types, while src/workspaces/intune/types also imports EventLogAnalysis from src/types/event-log. This creates a circular type dependency and couples shared event-log types to a workspace module. Consider moving IntuneTimestampBounds (or a generic TimestampBounds type) into a shared src/types/* module and have both sides import from there.
| function tryStart() { | ||
| const { graphApiEnabled, currentPlatform } = useUiStore.getState(); | ||
| if (!graphApiEnabled || currentPlatform !== "windows") return; | ||
| connectAndPopulate(); | ||
| } |
There was a problem hiding this comment.
This startup module may run before the platform-detection effect in Toolbar updates currentPlatform (ui-store defaults currentPlatform to "windows"). If a user has graphApiEnabled persisted as true on a non-Windows platform, this can still attempt Graph API commands and immediately error. Consider deriving the platform directly here (via Tauri platform()), or initializing currentPlatform deterministically before hydration-dependent startup logic runs.
| // Listen for progress events from the Rust backend | ||
| listen<{ channel: string; fetched: number }>("evtx-query-progress", (event) => { | ||
| useEvtxStore.setState({ | ||
| loadingChannel: event.payload.channel, | ||
| loadingProgress: event.payload.fetched, | ||
| }); | ||
| }); |
There was a problem hiding this comment.
This store sets up a Tauri event listener at module scope without retaining and disposing the unlisten function. In dev/HMR this can register multiple listeners, and in general it makes lifecycle management harder. Prefer setting up the listener inside a hook/effect with cleanup (as done elsewhere), or store the unlisten promise and expose a teardown/init function to call from a single top-level component.
| // Query all core channels in parallel (bypass queryChannels to avoid isLoading conflicts) | ||
| const mergeResult = (ch: string, result: EvtxParseResult) => { | ||
| console.log(`[evtx] ${ch}: got ${result.records.length} records, ${result.parseErrors} errors`, result.errorMessages); | ||
| const state = get(); | ||
| const merged = [...state.records, ...result.records]; | ||
| merged.sort((a, b) => a.timestampEpoch - b.timestampEpoch); | ||
| for (let i = 0; i < merged.length; i++) merged[i].id = i; | ||
|
|
There was a problem hiding this comment.
console.log in mergeResult will spam the console during live channel loading (especially when loading multiple core channels in parallel). Consider removing this or gating it behind a debug flag so normal users don’t get noisy logs.
| ## [Unreleased] — PR #82 | ||
|
|
||
| ### Added | ||
|
|
||
| - **Settings dialog** (replaces Accessibility dialog): Full settings UI with tabs for Appearance (themes, font size), Columns (visibility, ordering), Behavior (confirm tab close), Updates (auto-update toggle), and File Associations (Windows-only). Accessible via `Ctrl+,` or Window menu. | ||
| - **Context menu**: Right-click any log row for Copy Line, Copy Message, Jump to Line, Quick Filter by severity/component, Reveal in File Manager, and Error Lookup. Uses native Tauri menu popup for OS-native feel. | ||
| - **Event Log workspace** (Windows, feature-gated): Parse `.evtx` files and query live Windows Event Log channels. Supports file-based EVTX parsing with channel grouping, severity filtering, and correlation linking. Frontend workspace with channel sidebar, severity badges, and detail pane. | ||
| - **Event Log workspace** (Windows, feature-gated): Parse `.evtx` files and query live Windows Event Log channels. Supports file-based EVTX parsing with channel grouping, severity filtering, and correlation linking. Frontend workspace with channel sidebar, severity badges, and detail pane. Live queries use Win32 Event Log API (`EvtQuery`, `EvtRender`, `EvtFormatMessage`). "This Computer" auto-loads Application, System, Security, and Setup channels in parallel with progressive UI updates. Event Viewer-style nested tree sidebar (split on `-` and `/`) with resizable drag handle. Arrow key navigation, resizable detail pane, per-channel load/refresh buttons, and loading spinner with elapsed time in the status bar. | ||
| - **AppWorkload enrichment**: Parse "Get policies" JSON payloads in the log viewer to build GUID-to-app-name mappings. InfoPane shows resolved app names when log messages contain GUIDs, structured policy metadata cards, and decoded base64 PowerShell detection scripts via a lightweight syntax-highlighted code viewer. | ||
| - **Activity view**: New "Activity" toggle in the Intune timeline tab groups events by app into collapsible cards. Each card shows worst status, event count, duration, and event type badges. Expanded rows display parsed structured fields (intent, detection, applicability, reboot, GRS expired, enforcement) as colored tags with inline GUID resolution and word-wrapped detail messages. | ||
| - **GUID Registry dialog**: New Tools menu item showing a searchable table of all GUID-to-app-name mappings from the Intune analysis, with source confidence ranking (ApplicationName > Name > SetUpFilePath) and click-to-copy. | ||
| - **GUID Registry dialog**: New Tools menu item showing a searchable table of all GUID-to-app-name mappings from the Intune analysis, with source confidence ranking (GraphApi > ApplicationName > Name > SetUpFilePath) and click-to-copy. | ||
| - **Microsoft Graph API integration** (Windows, opt-in): Resolve Intune app GUIDs to display names via Microsoft Graph API. Authenticates silently using WAM (Web Account Manager) with the device's existing Entra ID session — no app registration required. Gated behind Settings > Graph API toggle (off by default) with consent warnings. Pre-populate cache fetches all apps, remediation scripts, platform scripts, and shell scripts in one call. GUID Registry dialog shows entries in tabbed view (All/Apps/Scripts/Remediations) with publisher and category columns. Auto-connects on startup when enabled, with status indicator in the status bar. | ||
| - **SideCarScriptDetectionManager events**: Extract PowerShell script detection lifecycle events (start, complete, exit code, process ID) as standalone PowerShellScript events in the Intune timeline. | ||
| - **Resizable InfoPane**: Drag handle between the log list and detail pane allows resizing (min 80px, max 70% viewport). | ||
| - **Jump to Line**: Context menu action to jump to a specific line number in the log. | ||
| - **Reveal in File Manager**: Context menu action to open the source file's location in Finder/Explorer. | ||
| - **Quick Filter**: Context menu action to instantly filter by the selected row's severity or component. | ||
| - **Multi-file unified timeline** (PR #81): Merge entries from multiple open log files into a single time-sorted view. Two entry points: "Merge Tabs..." button in the toolbar and "Merge into Timeline" button in the folder sidebar. Color-coded left borders distinguish source files. A legend bar provides per-file toggle visibility, correlation time window, and auto-correlate controls. Cross-file timestamp correlation highlights entries from other files within a configurable time window and shows them in the InfoPane with delta timestamps. | ||
| - **Session save/restore**: Save the current workspace state (open files, scroll positions, filters, merged tabs, workspace context) to a `.cmtrace` JSON file via File > Save Session (Ctrl+Shift+S). Restore via File > Open Session or Recent Sessions submenu. Files are integrity-checked with SHA-256 hashes — warns if files have changed or are missing since the session was saved. New `compute_file_hash` Rust backend command. | ||
| - **Log diff**: Compare two open log files side-by-side or in unified inline view. Fuzzy pattern matching normalizes GUIDs, timestamps, and long numbers so "same event, different instance" lines are recognized as matches. Stats bar shows common patterns vs. lines unique to each file. "Diff Tabs..." button in the toolbar opens a config dialog for source selection. | ||
| - **Sysmon EVTX workspace** (PR #72): Full Sysmon analysis workspace for Windows `.evtx` event log files. |
There was a problem hiding this comment.
The changelog entry claims a very broad set of features/PRs under “PR #82” (Graph API, unified timeline, session save/restore, log diff, sysmon, etc.). If this pull request is intended to be only the workspace registry refactor, the changelog looks out of scope/misleading; if the PR really includes these features, the PR title/description should be updated to reflect that scope so reviewers understand the risk/impact.
- event-log: remove incorrect DsregcmdSidebar, fix file filters to EVTX - deployment: handle file sources by analyzing parent directory - types: move IntuneTimestampBounds to shared types to break circular dep Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolve conflicts between workspace registry refactor and main's v1.1.0 features (Graph API, session save/restore, event log viewer). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
WorkspaceDefinitionsystem that replaces 25+ scattered if/else chains across AppShell, Toolbar, FileSidebar, and ui-storesrc/workspaces/(sysmon, dsregcmd, event-log, macos-diag, deployment, intune)SourceSummaryCardand sidebar primitives deduplicated tosrc/components/common/sidebar-primitives.tsx;getBaseNameconsolidated to single canonical exportWhat changed
New: Workspace Registry (
src/workspaces/)types.ts—WorkspaceDefinitioninterface with capabilities, file filters, action labels, status labels,onOpenSourcehandlersregistry.ts— CentralMap<WorkspaceId, WorkspaceDefinition>withgetWorkspace()andgetAvailableWorkspaces()Removed: Scattered workspace branching
WORKSPACE_PLATFORM_MAPin ui-store — deleted, delegates to registryWORKSPACE_LABELS,getOpenFileDialogFilters(),getOpenActionLabels()in Toolbar — deletedgetUiChromeStatus()— 8-way if/else replaced with 2-way capability checkopenSourceForWorkspace()— 5-way if/else replaced withworkspace.onOpenSourcelookuprenderWorkspace()in AppShell — 8-way if/else replaced with registry lookup + SuspensecommandStatecapability checks — workspace ID checks replaced withcapabilities.*flagsTest plan
npx tsc --noEmitpassesnpm run frontend:buildsucceeds🤖 Generated with Claude Code