feat: bulk operations, connection pooling, and migration CLI enhancements#19
feat: bulk operations, connection pooling, and migration CLI enhancements#19joshsmithxrm merged 49 commits intomainfrom
Conversation
- Add CodeQL workflow for C# static analysis (security-and-quality queries) - Add dependency-review-action to block PRs with high severity vulnerabilities - Add dotnet list package --vulnerable check to build workflow - Dependency check warns but doesn't fail (handles transitive dependency issues)
CLI Implementation: - Add ServiceFactory for DI container setup - Wire ExportCommand to IExporter (ParallelExporter) - Wire ImportCommand to IImporter (TieredImporter) - Wire AnalyzeCommand to ICmtSchemaReader + IDependencyGraphBuilder - Wire MigrateCommand for export→import flow - Fix import error order (validate file before connection) CMT Compatibility Fixes: - Add 'etc' attribute (ObjectTypeCode) to entity element - Change 'm2m' to 'manyToMany' for relationships - Add full relationship attributes (referencingEntity, referencingAttribute, etc.) - Add 'primaryKey' attribute support for fields - Add IsPrimaryKey property to FieldSchema 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `schema generate` command to create migration schemas from Dataverse metadata - Add `schema list` command to browse available entities with filtering - Write CMT-compatible schema format (etc, primaryidfield, lookupType, relationships) - Handle polymorphic lookups (e.g., account|contact) in dependency analysis - Add entityreference type to IsLookup detection - Include explicit <relationships> section for enhanced dependency detection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dateMode="absolute" attribute to schema root (required by CMT) - Add <entityImportOrder> section to schema (required by CMT) - Change data.xml to use element content for values instead of attributes - Update date format to CMT-compatible "yyyy-MM-dd HH:mm:ss" - Update boolean format to "1"/"0" instead of "true"/"false" Fixes "Invalid import file" error when importing into CMT. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Read lookup GUID from element content (CMT format) - Add "entityreference" to lookup type handling - Fix boolean parsing to handle "1"/"0" values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add [Content_Types].xml to ZIP (required by CMT) - Use value attribute instead of element content for field values - Add xmlns:xsd and xmlns:xsi namespaces to data.xml root - Use displayname attribute on entity (not recordcount) - Include primary ID field in record output - Add m2mrelationships element after records - Fix DateTime format to ISO 8601 with 7 decimal places - Remove dateMode attribute and entityImportOrder from schema - Remove customfield attribute from field elements - HTML-encode filter content using WriteElementString - Fix field attribute order: displayname, name, type 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ibility - Add IsReflexive and TargetEntityPrimaryKey to RelationshipSchema - Create ManyToManyRelationshipData class with grouped target model - Update CmtSchemaReader/Writer to handle M2M attributes (isreflexive, m2mTargetEntityPrimaryKey) - Update CmtDataReader to parse <m2mrelationships> element - Update CmtDataWriter to write <m2mrelationships> with grouped targets - Add M2M export to ParallelExporter (queries intersect entities) - Rewrite ProcessRelationshipsAsync in TieredImporter with role entity lookup - Support AssociateRequest with multiple targets per source 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Attribute Filtering: - Add IncludeAttributes, ExcludeAttributes, ExcludeAttributePatterns to SchemaGeneratorOptions - Update DataverseSchemaGenerator to apply attribute filtering - Add CLI options: --include-attributes, --exclude-attributes, --exclude-patterns User Mapping: - Add UserMapping and UserMappingCollection models - Add UserMappingReader for XML user mapping files - Update TieredImporter to apply user mappings for systemuser/team references - Add CLI option: --user-mapping Plugin Disable/Enable: - Add PluginStepManager to query and disable/enable plugin steps - Update TieredImporter to disable plugins during import based on schema disableplugins attribute - Re-enable plugins in finally block to ensure cleanup - Register IPluginStepManager in DI container 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The M2M relationship Entity1/Entity2 must be relative to the current entity being processed, not the fixed order from Dataverse metadata. Bug: When Dataverse returned Entity1LogicalName != current entity, we would set Entity2 to the wrong entity, causing: - systemuser M2M to team → exported with targetentityname="systemuser" - Import then looks for team with systemuser's GUID → fails Fix: Determine source/target based on which entity matches metadata.LogicalName - Also set IsReflexive for self-referencing M2M relationships - Set TargetEntityPrimaryKey from the target intersect attribute 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](actions/setup-dotnet@v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
--- updated-dependencies: - dependency-name: coverlet.collector dependency-version: 6.0.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: coverlet.collector dependency-version: 6.0.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: coverlet.collector dependency-version: 6.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
--- updated-dependencies: - dependency-name: FluentAssertions dependency-version: 8.8.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
--- updated-dependencies: - dependency-name: Microsoft.Extensions.DependencyInjection dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.DependencyInjection dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
…Microsoft.Extensions.Logging.Abstractions Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 8.0.2 to 10.0.1 Bumps Microsoft.Extensions.Logging.Abstractions from 8.0.3 to 10.0.1 --- updated-dependencies: - dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Logging.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Logging.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
…Microsoft.Extensions.Options Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 8.0.2 to 10.0.1 Bumps Microsoft.Extensions.Options from 8.0.2 to 10.0.1 --- updated-dependencies: - dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Options dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: Microsoft.Extensions.Options dependency-version: 10.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Add validation in DataverseConnectionPool that detects when connections target different Dataverse organizations and logs a warning. This prevents the common misconfiguration of putting Dev/QA/Prod in the same pool, which causes requests to be randomly load-balanced across environments. Also add documentation in README explaining: - Why multiple orgs in one pool is wrong - The correct pattern for multi-environment scenarios - When multiple connections in one pool IS appropriate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PPDS.Dataverse: - Add ProgressTracker utility for thread-safe progress calculation - Add ProgressSnapshot record with instant/overall rates and ETA - Add MaxParallelBatches option to BulkOperationOptions - Implement parallel batch processing in BulkOperationExecutor - Convert BulkOperationResult to record for immutability PPDS.Migration: - Fix Entity.Id not used by UpsertMultiple (add as attribute) - Add SuccessCount/FailureCount to ProgressEventArgs - Fix TieredImporter to report success/failure breakdown - Fix deferred fields progress to set Field, Current, Total - Pass Errors array to progress.Complete() ConsoleProgressReporter: - Show success/failure breakdown during import - Display detailed errors in completion summary (up to 10) - Handle null Field gracefully in deferred fields display - Add color-coded output for success/warnings/errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the duplicate key error that occurs when setting alternate key columns in both KeyAttributes and Attributes. The server's internal ClassifyEntitiesForUpdateAndCreateV2 processor copies KeyAttributes into Attributes, causing Dictionary.Insert to fail with "An item with the same key has already been added". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add IProgress<ProgressSnapshot> parameter to IBulkOperationExecutor methods
- Wire up ProgressTracker in BulkOperationExecutor for real-time progress
- Report progress after each batch completion (both parallel and sequential)
Usage:
var progress = new Progress<ProgressSnapshot>(snapshot =>
Console.WriteLine($"{snapshot.Processed}/{snapshot.Total} ({snapshot.PercentComplete:F1}%)"));
await executor.UpsertMultipleAsync(entityName, entities, options, progress);
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add LogDebug calls before and after each batch execution in BulkOperationExecutor for CreateMultiple, UpdateMultiple, and UpsertMultiple operations. With --verbose (Debug level logging), users will now see: dbug: Executing UpsertMultiple batch. Entity: account, BatchSize: 1000 dbug: UpsertMultiple batch completed. Entity: account, Success: 1000 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…play - Add RatePerSecond property that returns OverallRatePerSecond - Add warning to InstantRatePerSecond about volatility in batch operations - Add BULK_OPERATIONS_BENCHMARKS.md to document performance testing The InstantRatePerSecond fluctuates wildly when batches complete in bursts. Use RatePerSecond (overall rate) for display and throughput reporting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix InitializeMinimumConnections to count active connections, not just idle ones. Previously, validation loop created new connections every 60s when active connections weren't counted toward the minimum. - Add PoolExhaustedException for typed exception handling - Add retry logic with exponential backoff (1s, 2s) for pool exhaustion - Fix dead code in retry loop where final attempt was unreachable 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pool is empty but connections are active (about to be returned), add a brief 5ms spin-wait before creating a new connection. This handles the race condition where: 1. Worker A logs "batch completed" but hasn't returned connection yet 2. Worker B starts new batch and sees empty pool 3. Worker B creates new connection (unnecessary) 4. Worker A's connection is then returned (now we have an extra) The spin-wait allows in-flight connection returns to complete, reducing unnecessary pool expansion from 50 connections down to ~5-8 for a 4-worker parallel batch operation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…osal flag The PooledClient._disposed flag was set on first Dispose() and never reset, causing subsequent checkouts of the same connection to silently skip returning to pool. This caused connection exhaustion under load. Changes: - Rename _disposed to _returned to clarify semantics (returning to pool, not disposing) - Reset _returned flag in Reset() when connection is returned to pool - Add _poolLock for synchronized queue access - Use Interlocked operations for thread-safe flag management - Pass CancellationToken through Parallel.ForEachAsync to batch methods 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Results from testing connection pool vs single ServiceClient: - Connection pool is 5% faster than single ServiceClient (47.7/s vs 45.4/s) - Batch size 100 is 3% faster than batch size 1000 - Updates are ~23% slower than creates (alternate key lookup overhead) Optimal config: Connection Pool + Batch Size 100 = 47.7 records/sec 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update CLAUDE.md with PPDS.Dataverse project structure and performance rules - Add Microsoft's reference throughput benchmarks (10M records/hour for bulk APIs) - Add batch size guidance based on our benchmarks (100 vs 1000) - Add RecommendedDegreesOfParallelism / x-ms-dop-hint guidance - Add Performance Settings section documenting auto-applied settings - Add Microsoft Learn reference links to all ADRs - Document service protection limits (6K requests, 20min execution, 52 concurrent) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change BatchSize default from 1000 to 100 (benchmarked optimal) - Change MaxParallelBatches to nullable, default null - When null, automatically use ServiceClient.RecommendedDegreesOfParallelism (from x-ms-dop-hint header per Microsoft recommendation) - Add ResolveParallelismAsync helper to resolve parallelism for all bulk ops - Fall back to sequential (1) if RecommendedDegreesOfParallelism unavailable 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Log warning if MaxParallelBatches > MaxPoolSize since effective parallelism will be limited by available pool connections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two comprehensive specification documents for enterprise-grade features: 1. THROTTLE_DETECTION_AND_ROUTING.md - Wire up existing ThrottleTracker infrastructure - Detect service protection errors (all 3 error codes) - Extract Retry-After from OrganizationServiceFault.ErrorDetails - Intelligent routing: try different connection first, wait only when all throttled - Expose throttle statistics to consumers 2. CONNECTION_HEALTH_MANAGEMENT.md - Health-based connection recycling (not fixed timer) - Connection validation on checkout (IsReady, age, validity) - Auth and connection failure detection and recovery - MarkInvalid() for explicit connection invalidation - Retry failed operations with new connections - Configurable MaxLifetime (default 60min vs current 30min) Both specs include: - Problem statement and Microsoft guidance with references - Current state analysis - Detailed implementation with code examples - Testing requirements and acceptance criteria - Risk mitigations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add parallelism 50 results showing 508.6 rec/s (8.4x improvement over server-recommended). Document when to use standard vs high-throughput mode and note that multi-app-registration pooling is untested but could potentially increase throughput further. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused variable in ParallelExporter.cs (error) - Refactor foreach loops to use LINQ Where/Select patterns - Improve exception handling in DataverseSchemaGenerator.cs with specific catch blocks Files changed: - ParallelExporter.cs: Remove dead code, use LINQ for filtering - SchemaGeneratorOptions.cs: Replace foreach+if with LINQ Any - CmtDataReader.cs: Use LINQ for parsing target IDs - ThrottleTracker.cs: Simplify cleanup with LINQ Where - DependencyGraphBuilder.cs: Use LINQ pipeline for edge creation - DataverseConnectionPool.cs: Use LINQ for connection string parsing - DataverseSchemaGenerator.cs: Add specific exception catches 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add direct reference to System.Security.Cryptography.Pkcs 8.0.x to override the vulnerable 6.0.1 version pulled in by Dataverse.Client. Resolves: GHSA-555c-2p6r-68mm (High severity) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…Microsoft.Extensions.Logging.Abstractions
- Add ExecuteAsync to pool that retries indefinitely on service protection - PooledClient auto-records throttle via callback to pool - GetClientAsync waits for non-throttled connection BEFORE acquiring semaphore - ThrottleAwareStrategy filters throttled connections, falls back to shortest expiry - BulkOperationExecutor simplified: no MaxThrottleRetries, pool handles waiting - Service protection is transient - never fail, only CancellationToken stops retry Key fix: Throttle waiting no longer holds semaphore slots, preventing PoolExhaustedException when all connections are throttled. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
f56dacd to
fd32687
Compare
Removed the unused `lastException` variable and its assignments in ExecuteBatchWithThrottleHandlingAsync. The variable was assigned in 4 catch blocks but never read - each catch block either throws the original exception or continues to retry. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@gemini-code-assist review |
There was a problem hiding this comment.
Code Review
This is a massive and impressive feature release that adds high-performance bulk operations, intelligent connection pooling, and a comprehensive migration CLI. The level of detail in the new documentation, ADRs, and specifications is excellent and provides great context for the design decisions. The implementation is generally of very high quality, introducing sophisticated and resilient patterns for parallelism, throttle handling, and error recovery. I've identified one critical issue regarding a potential stack overflow in the connection pool and a medium-severity maintainability issue in a constructor. Overall, this is a fantastic contribution that significantly enhances the SDK's capabilities.
There was a problem hiding this comment.
Copilot reviewed 68 out of 68 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Replaced recursive call in GetConnectionFromPoolCore with a while loop that drains invalid connections. This eliminates theoretical stack overflow risk while maintaining identical behavior: - Loop continues until valid connection found OR pool is empty - Invalid connections are disposed and removed from pool - When pool exhausted, creates new connection - Slightly more efficient (no function call overhead per iteration) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- ADR-0005: Pool sizing per connection (MaxConnectionsPerUser default) - Structured Configuration Spec: Typed config with Key Vault/env var support - Multi-Environment Spec: Named environments and live migration design These specs document the approved designs for implementation on a future branch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…es (#19) Bumps the development-dependencies group with 4 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser), [@vscode/vsce](https://github.com/Microsoft/vsce) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `@typescript-eslint/eslint-plugin` from 8.47.0 to 8.48.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.47.0 to 8.48.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/parser) Updates `@vscode/vsce` from 3.7.0 to 3.7.1 - [Release notes](https://github.com/Microsoft/vsce/releases) - [Commits](microsoft/vscode-vsce@v3.7.0...v3.7.1) Updates `typescript-eslint` from 8.47.0 to 8.48.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.48.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.48.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: "@typescript-eslint/parser" dependency-version: 8.48.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: "@vscode/vsce" dependency-version: 3.7.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: typescript-eslint dependency-version: 8.48.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bug #11: Export now works with FetchXML queries. Added fetchXml parameter to query/export RPC endpoint so FetchXML content is sent directly instead of through the SQL parser (which crashes on XML). Bug #15: Added expand chevron (›) indicator on solution component items so users can discover they're clickable for detail cards. Bug #18: Removed auto-collapse on component detail cards — multiple cards can now be expanded simultaneously for comparison. Bug #19: Solution list now shows uniqueName (friendlyName) format instead of friendlyName only, matching developer workflow expectations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug #11: Export now works with FetchXML queries. Added fetchXml parameter to query/export RPC endpoint so FetchXML content is sent directly instead of through the SQL parser (which crashes on XML). Bug #15: Added expand chevron (›) indicator on solution component items so users can discover they're clickable for detail cards. Bug #18: Removed auto-collapse on component detail cards — multiple cards can now be expanded simultaneously for comparison. Bug #19: Solution list now shows uniqueName (friendlyName) format instead of friendlyName only, matching developer workflow expectations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls, Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged end-to-end C# support. Import Jobs (#7,#8,#9): Search bar, Operation Context column (end-to-end C#→TS), record count with filtered status. Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown fix, Maker Portal URL fix (Dynamics 365 classic), status text labels, record count, search bar. Web Resources (#19): Restored Created By and Created On columns. Connection References (#23,#24,#25,#28,#55): Expandable flow/connection detail with chevron toggle, ISO timestamp formatting, search bar, status badge improvements (Unknown/Unbound), Sync Settings button. Environment Variables (#29,#31,#55): Modified On column restored, search bar, Sync Settings button. Metadata Browser (#37): Custom Only filter toggle for entities. Data Explorer (#41,#42): Clear button, Import button (file dialog). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls, Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged end-to-end C# support. Import Jobs (#7,#8,#9): Search bar, Operation Context column (end-to-end C#→TS), record count with filtered status. Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown fix, Maker Portal URL fix (Dynamics 365 classic), status text labels, record count, search bar. Web Resources (#19): Restored Created By and Created On columns. Connection References (#23,#24,#25,#28,#55): Expandable flow/connection detail with chevron toggle, ISO timestamp formatting, search bar, status badge improvements (Unknown/Unbound), Sync Settings button. Environment Variables (#29,#31,#55): Modified On column restored, search bar, Sync Settings button. Metadata Browser (#37): Custom Only filter toggle for entities. Data Explorer (#41,#42): Clear button, Import button (file dialog). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cdp): use pwsh Expand-Archive for VSIX extraction on Windows bsdtar interprets the C: drive prefix as a remote host, breaking VSIX extraction in --vsix mode. Use PowerShell's Expand-Archive on Windows; keep tar on other platforms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * plan: extension UX audit fixes — 28 findings across 10 phases Side-by-side comparison of legacy v0.3.4 vs new extension produced 55 findings. After triage: 28 fixes, 22 keep-new-behavior, 5 deferred. Organized into 10 phases (1 cross-cutting + 9 per-panel) for parallel agent execution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ext): Phase 1 — cross-cutting infrastructure fixes - Add Connection References + Environment Variables to sidebar Tools (#56, #57) - Standardize command titles: "Open Data Explorer", "Open Plugin Traces" (#51) - Remove text-transform: uppercase from 5 panel CSS files for Title Case headers (#10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(ext): Phases 2-9 — UX audit fixes across all 8 panels Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls, Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged end-to-end C# support. Import Jobs (#7,#8,#9): Search bar, Operation Context column (end-to-end C#→TS), record count with filtered status. Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown fix, Maker Portal URL fix (Dynamics 365 classic), status text labels, record count, search bar. Web Resources (#19): Restored Created By and Created On columns. Connection References (#23,#24,#25,#28,#55): Expandable flow/connection detail with chevron toggle, ISO timestamp formatting, search bar, status badge improvements (Unknown/Unbound), Sync Settings button. Environment Variables (#29,#31,#55): Modified On column restored, search bar, Sync Settings button. Metadata Browser (#37): Custom Only filter toggle for entities. Data Explorer (#41,#42): Clear button, Import button (file dialog). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ext): review fixes — colSpan bug and command injection - Connection References: fix colCount from wrong heuristic (8) to correct value (7) matching actual column count - CDP tool: sanitize paths for PowerShell injection (escape single quotes); use execFileSync for tar on Unix to avoid shell interpretation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style(ext): extract inline styles to CSS classes per Gemini review Move search input and sort select inline styles to dedicated .toolbar-search and .toolbar-select CSS classes across 4 panels (Connection Refs, Env Variables, Import Jobs, Solutions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ext): add missing webview entry points to knip config The 6 non-query/solutions webview panels are esbuild entry points but were missing from knip.json, causing false-positive unused-file reports. Also un-export internal-only types from shared modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ext): solution filter GUID bug and raw ISO timestamps - SolutionFilter shared component used uniqueName as option value instead of GUID id, causing "solutionId must be a valid GUID" error on Web Resources (and silently wrong on Conn Refs / Env Vars) - Import Jobs and Web Resources rendered raw ISO timestamps; add formatDateTime helper matching Plugin Traces / Conn Refs pattern Found by QA blind verification agents. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ext): review fixes — escaping, shell safety, URL normalization - Solutions panel: escape rootComponentBehavior and boolean ternaries before innerHTML insertion (S1 compliance) - Connection References: escape literal "Unbound" for consistent escaping discipline - CDP tool: use execFileSync instead of execSync for PowerShell VSIX extraction (S2 compliance — no shell: true) - Plugin Traces: strip trailing slash from environment URL before Maker Portal link construction Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ext): escape formatDate output in solutions detail card Wrap formatDate() calls in escapeHtml() for consistent escaping discipline — formatDate can return raw ISO string on parse failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Major feature release adding high-performance bulk operations, intelligent connection pooling, and migration CLI tooling.
Bulk Operations (PPDS.Dataverse)
CreateMultiple,UpdateMultiple,UpsertMultipleAPIsIProgress<ProgressSnapshot>for real-time throughput metricsRecommendedDegreesOfParallelism(can be overridden for higher throughput)Connection Pooling
Resilience & Retry Logic
Migration CLI (
ppds-migrate)Documentation
CI/CD
Test Results
Validation Status
Breaking Changes
None. All changes are additive.
Commits
🤖 Generated with Claude Code