Signing executables for all platform#377
Conversation
Bundle Size Report 📦
Bundle Analysis ReportsThe detailed bundle analysis reports are available in the workflow artifacts:
Download the artifacts from the workflow run to view interactive visualizations. Bundle size tracking is now active! This helps prevent bundle bloat. |
There was a problem hiding this comment.
Pull request overview
This PR updates the release workflows to ensure packaged artifacts are properly signed/notarized across platforms and that published update metadata reflects any post-processing (e.g., Windows signing, macOS stapling).
Changes:
- Enable recursive signing for Windows artifacts and repackage portable ZIPs to include the signed EXE.
- Add steps to regenerate
latest*.ymlupdate metadata for Windows, Linux, and macOS after artifacts are modified. - Apply the same workflow logic to both stable (prod) and nightly releases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 16 comments.
| File | Description |
|---|---|
.github/workflows/prod-release.yml |
Adds ZIP repackaging and update-metadata regeneration steps around signing/notarization for stable releases. |
.github/workflows/nightly-release.yml |
Mirrors the same signing + repackaging + update-metadata regeneration changes for insider/nightly releases. |
| # Calculate SHA256 hash | ||
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | ||
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | ||
|
|
||
| echo " SHA256: $HASH" | ||
| echo " Size: $SIZE" | ||
|
|
||
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | ||
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | ||
| "$VERSION" \ | ||
| "$(basename "$APP_IMAGE")" \ | ||
| "$HASH" \ |
There was a problem hiding this comment.
This regeneration writes sha512: null and only computes a sha256 hex hash. electron-updater update metadata expects a valid sha512 for the artifact; setting it to null is expected to break update downloads. Compute and populate the correct sha512 value for the AppImage (and ideally update the existing YAML entry instead of rewriting the whole file).
| # Calculate SHA256 hash | |
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| "$HASH" \ | |
| # Calculate SHA256 hash (hex) and SHA512 hash (base64, as expected by electron-updater) | |
| SHA256_HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SHA512_HASH=$(openssl dgst -sha512 -binary "$APP_IMAGE" | base64 -w0 2>/dev/null || openssl dgst -sha512 -binary "$APP_IMAGE" | base64) | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $SHA256_HASH" | |
| echo " SHA512 (base64): $SHA512_HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: %s\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| "$SHA512_HASH" \ | |
| "$SHA256_HASH" \ |
| # Calculate SHA256 hash | ||
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | ||
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | ||
|
|
||
| echo " SHA256: $HASH" | ||
| echo " Size: $SIZE" | ||
|
|
||
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | ||
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | ||
| "$VERSION" \ | ||
| "$(basename "$APP_IMAGE")" \ |
There was a problem hiding this comment.
This regeneration writes sha512: null and only computes a sha256 hex hash. electron-updater update metadata expects a valid sha512 for the artifact; setting it to null is expected to break update downloads. Compute and populate the correct sha512 value for the AppImage (and ideally update the existing YAML entry instead of rewriting the whole file).
| # Calculate SHA256 hash | |
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| # Calculate SHA256 and SHA512 hashes | |
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SHA512=$(sha512sum "$APP_IMAGE" | awk '{print $1}') | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: %s\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| "$SHA512" \ |
| # Find all YAML files | ||
| YML_FILES=$(find "$BUILD_DIR" -name "latest*.yml" -o -name "*-linux.yml") | ||
|
|
||
| if [[ -z "$YML_FILES" ]]; then | ||
| echo "⚠️ No YAML files found, skipping regeneration" | ||
| exit 0 | ||
| fi | ||
|
|
||
| for YML_FILE in $YML_FILES; do | ||
| echo "Processing: $YML_FILE" | ||
|
|
||
| # Extract version from existing YAML | ||
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") | ||
|
|
||
| # Find the main AppImage file | ||
| APP_IMAGE=$(find "$BUILD_DIR" -maxdepth 1 -type f -name "*.AppImage" | head -n 1) | ||
|
|
There was a problem hiding this comment.
This Linux step rewrites every YAML matching latest*.yml (and *-linux.yml) with a single-entry template for the first *.AppImage found. That can accidentally clobber other update metadata files (or future additional entries) and makes the result dependent on file ordering. Consider targeting only the intended Linux update file(s) (e.g., latest-linux.yml) and updating the hash/size for the URL already present in that YAML instead of replacing the whole document.
| # Find the main EXE file (look for the installer) | ||
| $exeFiles = @(Get-ChildItem "$buildDir/*.exe" -ErrorAction SilentlyContinue) | ||
|
|
||
| if ($exeFiles.Count -gt 0) { | ||
| # Sort to get the latest/main installer (NSIS or main app exe) | ||
| $mainExe = $exeFiles | Where-Object { $_.Name -match "(NSIS|Setup|Installer)" } | Select-Object -First 1 | ||
| if (-not $mainExe) { | ||
| $mainExe = $exeFiles[0] # Fallback to first exe | ||
| } |
There was a problem hiding this comment.
The latest.yml regeneration guesses the “main” installer by picking the first EXE whose name matches (NSIS|Setup|Installer) without any deterministic sorting. This can select the wrong EXE (or vary run-to-run) and produce incorrect hashes. Prefer reading the existing latest.yml to get the exact files[0].url/path value and hash that file, or sort candidates deterministically (e.g., by LastWriteTime / size).
| # Extract version from existing YAML | ||
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") |
There was a problem hiding this comment.
grep -oP is used to extract version: in this macOS job. On macos-latest, the default BSD grep typically does not support -P, which can make this step fail at runtime. Use a POSIX-compatible approach (e.g., sed/awk), or explicitly install GNU grep and use ggrep -P.
| # Extract version from existing YAML | |
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") | |
| # Extract version from existing YAML (POSIX-compatible, avoids grep -P) | |
| VERSION=$(awk '/^[[:space:]]*version:[[:space:]]*/ { print $2; exit }' "$YML_FILE") | |
| VERSION=${VERSION:-unknown} |
| # Find all YAML files | ||
| YML_FILES=$(find "$BUILD_DIR" -name "latest*.yml" -o -name "*-linux.yml") | ||
|
|
||
| if [[ -z "$YML_FILES" ]]; then | ||
| echo "⚠️ No YAML files found, skipping regeneration" | ||
| exit 0 | ||
| fi | ||
|
|
||
| for YML_FILE in $YML_FILES; do | ||
| echo "Processing: $YML_FILE" | ||
|
|
||
| # Extract version from existing YAML | ||
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") | ||
|
|
||
| # Find the main AppImage file | ||
| APP_IMAGE=$(find "$BUILD_DIR" -maxdepth 1 -type f -name "*.AppImage" | head -n 1) | ||
|
|
||
| if [[ -n "$APP_IMAGE" && -f "$APP_IMAGE" ]]; then | ||
| echo " Found AppImage: $(basename "$APP_IMAGE")" | ||
|
|
||
| # Calculate SHA256 hash | ||
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | ||
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | ||
|
|
||
| echo " SHA256: $HASH" | ||
| echo " Size: $SIZE" | ||
|
|
||
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | ||
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | ||
| "$VERSION" \ | ||
| "$(basename "$APP_IMAGE")" \ | ||
| "$HASH" \ | ||
| "$SIZE" \ | ||
| "$(date -u +'%Y-%m-%dT%H:%M:%S.000Z')" > "$YML_FILE" | ||
| echo " ✅ Updated $YML_FILE" | ||
| else | ||
| echo " ⚠️ No AppImage found in $BUILD_DIR" | ||
| fi | ||
| done |
There was a problem hiding this comment.
This Linux step rewrites every YAML matching latest*.yml (and *-linux.yml) with a single-entry template for the first *.AppImage found. That can accidentally clobber other update metadata files (or future additional entries) and makes the result dependent on file ordering. Consider targeting only the intended Linux update file(s) (e.g., latest-linux.yml) and updating the hash/size for the URL already present in that YAML instead of replacing the whole document.
| # Find all YAML files | |
| YML_FILES=$(find "$BUILD_DIR" -name "latest*.yml" -o -name "*-linux.yml") | |
| if [[ -z "$YML_FILES" ]]; then | |
| echo "⚠️ No YAML files found, skipping regeneration" | |
| exit 0 | |
| fi | |
| for YML_FILE in $YML_FILES; do | |
| echo "Processing: $YML_FILE" | |
| # Extract version from existing YAML | |
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") | |
| # Find the main AppImage file | |
| APP_IMAGE=$(find "$BUILD_DIR" -maxdepth 1 -type f -name "*.AppImage" | head -n 1) | |
| if [[ -n "$APP_IMAGE" && -f "$APP_IMAGE" ]]; then | |
| echo " Found AppImage: $(basename "$APP_IMAGE")" | |
| # Calculate SHA256 hash | |
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| "$HASH" \ | |
| "$SIZE" \ | |
| "$(date -u +'%Y-%m-%dT%H:%M:%S.000Z')" > "$YML_FILE" | |
| echo " ✅ Updated $YML_FILE" | |
| else | |
| echo " ⚠️ No AppImage found in $BUILD_DIR" | |
| fi | |
| done | |
| # Target only the Linux update metadata file to avoid clobbering other YAMLs | |
| YML_FILE="$BUILD_DIR/latest-linux.yml" | |
| if [[ ! -f "$YML_FILE" ]]; then | |
| echo "⚠️ latest-linux.yml not found in $BUILD_DIR, skipping regeneration" | |
| exit 0 | |
| fi | |
| echo "Processing: $YML_FILE" | |
| # Extract version from existing YAML | |
| VERSION=$(grep -oP 'version:\s+\K[^\s]+' "$YML_FILE" || echo "unknown") | |
| # Find the main AppImage file | |
| APP_IMAGE=$(find "$BUILD_DIR" -maxdepth 1 -type f -name "*.AppImage" | head -n 1) | |
| if [[ -n "$APP_IMAGE" && -f "$APP_IMAGE" ]]; then | |
| echo " Found AppImage: $(basename "$APP_IMAGE")" | |
| # Calculate SHA256 hash | |
| HASH=$(sha256sum "$APP_IMAGE" | awk '{print $1}') | |
| SIZE=$(stat -c %s "$APP_IMAGE" 2>/dev/null || stat -f %z "$APP_IMAGE" 2>/dev/null) | |
| echo " SHA256: $HASH" | |
| echo " Size: $SIZE" | |
| # Create new YAML with correct hashes using printf to avoid YAML parsing issues | |
| printf "version: %s\nfiles:\n - url: %s\n sha512: null\n sha256: %s\n size: %s\n blockMapSize: null\nreleaseDate: %s\n" \ | |
| "$VERSION" \ | |
| "$(basename "$APP_IMAGE")" \ | |
| "$HASH" \ | |
| "$SIZE" \ | |
| "$(date -u +'%Y-%m-%dT%H:%M:%S.000Z')" > "$YML_FILE" | |
| echo " ✅ Updated $YML_FILE" | |
| else | |
| echo " ⚠️ No AppImage found in $BUILD_DIR" | |
| fi |
| # Find the main EXE file (look for the installer) | ||
| $exeFiles = @(Get-ChildItem "$buildDir/*.exe" -ErrorAction SilentlyContinue) | ||
|
|
||
| if ($exeFiles.Count -gt 0) { | ||
| # Sort to get the latest/main installer (NSIS or main app exe) | ||
| $mainExe = $exeFiles | Where-Object { $_.Name -match "(NSIS|Setup|Installer)" } | Select-Object -First 1 | ||
| if (-not $mainExe) { | ||
| $mainExe = $exeFiles[0] # Fallback to first exe | ||
| } | ||
|
|
There was a problem hiding this comment.
The latest.yml regeneration guesses the “main” installer by picking the first EXE whose name matches (NSIS|Setup|Installer) without any deterministic sorting. This can select the wrong EXE (or vary run-to-run) and produce incorrect hashes. Prefer reading the existing latest.yml to get the exact files[0].url/path value and hash that file, or sort candidates deterministically (e.g., by LastWriteTime / size).
| # Find the main EXE file (look for the installer) | |
| $exeFiles = @(Get-ChildItem "$buildDir/*.exe" -ErrorAction SilentlyContinue) | |
| if ($exeFiles.Count -gt 0) { | |
| # Sort to get the latest/main installer (NSIS or main app exe) | |
| $mainExe = $exeFiles | Where-Object { $_.Name -match "(NSIS|Setup|Installer)" } | Select-Object -First 1 | |
| if (-not $mainExe) { | |
| $mainExe = $exeFiles[0] # Fallback to first exe | |
| } | |
| # Try to extract the URL of the main installer from existing latest.yml (files[0].url) | |
| $mainExeName = $null | |
| $mainExeNameMatch = [regex]::Match($ymlContent, 'files:\s*\r?\n\s*-\s+url:\s+([^\r\n]+)') | |
| if ($mainExeNameMatch.Success) { | |
| $mainExeNameRaw = $mainExeNameMatch.Groups[1].Value.Trim() | |
| # Remove optional surrounding quotes from the URL value | |
| $mainExeName = $mainExeNameRaw.Trim('"').Trim("'") | |
| } | |
| # Find the main EXE file deterministically | |
| $exeFiles = @(Get-ChildItem "$buildDir/*.exe" -ErrorAction SilentlyContinue | Sort-Object -Property Name) | |
| if ($exeFiles.Count -gt 0) { | |
| $mainExe = $null | |
| # Prefer the EXE referenced in existing latest.yml, if present | |
| if ($mainExeName) { | |
| $mainExe = $exeFiles | Where-Object { $_.Name -eq $mainExeName } | Select-Object -First 1 | |
| } | |
| # Fallback: prefer installer-like names from the sorted list | |
| if (-not $mainExe) { | |
| $installerCandidates = $exeFiles | Where-Object { $_.Name -match "(NSIS|Setup|Installer)" } | |
| if ($installerCandidates) { | |
| $mainExe = $installerCandidates | Select-Object -First 1 | |
| } | |
| } | |
| # Final fallback: first EXE in the deterministically sorted list | |
| if (-not $mainExe) { | |
| $mainExe = $exeFiles[0] | |
| } | |
| $signedExe = Get-ChildItem $buildDir -Recurse -Filter $zipExe.Name -ErrorAction SilentlyContinue | Select-Object -First 1 | ||
| if ($signedExe) { | ||
| Copy-Item $signedExe.FullName $zipExe.FullName -Force | ||
| Write-Host " Replaced $($zipExe.Name) with signed binary." | ||
| } else { | ||
| Write-Host " No signed match found for $($zipExe.Name)." | ||
| } | ||
| } | ||
|
|
||
| Remove-Item $zip.FullName -Force | ||
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force |
There was a problem hiding this comment.
Portable ZIP repack: the replacement EXE is chosen by name with Get-ChildItem ... -Recurse -Filter $zipExe.Name | Select-Object -First 1. If multiple EXEs share a name under build/ (common with unpacked directories), this can copy the wrong binary into the ZIP. Consider matching by expected relative path, verifying the candidate is Authenticode-signed before copying, and cleaning up $tempDir after repacking to avoid leaking temp directories.
| $signedExe = Get-ChildItem $buildDir -Recurse -Filter $zipExe.Name -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($signedExe) { | |
| Copy-Item $signedExe.FullName $zipExe.FullName -Force | |
| Write-Host " Replaced $($zipExe.Name) with signed binary." | |
| } else { | |
| Write-Host " No signed match found for $($zipExe.Name)." | |
| } | |
| } | |
| Remove-Item $zip.FullName -Force | |
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force | |
| # Determine the EXE's relative path inside the ZIP and map it to the build directory | |
| $relativePath = $zipExe.FullName.Substring($tempDir.Length).TrimStart('\', '/') | |
| $candidatePath = Join-Path $buildDir $relativePath | |
| if (Test-Path -LiteralPath $candidatePath) { | |
| $candidateItem = Get-Item -LiteralPath $candidatePath | |
| if (-not $candidateItem.PSIsContainer) { | |
| $signature = Get-AuthenticodeSignature -FilePath $candidateItem.FullName | |
| if ($signature -and $signature.Status -eq 'Valid') { | |
| Copy-Item $candidateItem.FullName $zipExe.FullName -Force | |
| Write-Host " Replaced $($zipExe.Name) with signed binary at relative path '$relativePath'." | |
| } else { | |
| Write-Host " Skipping replacement for $($zipExe.Name) at relative path '$relativePath' due to invalid or missing Authenticode signature." | |
| } | |
| } else { | |
| Write-Host " Skipping replacement for $($zipExe.Name); expected file but found directory at relative path '$relativePath'." | |
| } | |
| } else { | |
| Write-Host " No signed match found for $($zipExe.Name) at relative path '$relativePath'." | |
| } | |
| } | |
| Remove-Item $zip.FullName -Force | |
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force | |
| # Clean up temporary directory to avoid leaking temp folders on the runner | |
| Remove-Item $tempDir -Recurse -Force |
| $yml = @{ | ||
| version = $version | ||
| files = @( | ||
| @{ | ||
| url = $mainExe.Name | ||
| sha512 = $null | ||
| sha256 = $hash | ||
| size = $size | ||
| blockMapSize = $null | ||
| } | ||
| ) | ||
| releaseDate = $releaseDate | ||
| } |
There was a problem hiding this comment.
$yml = @{ ... } is constructed but never used (the step manually builds $newYmlContent). Removing the unused $yml block will reduce confusion and keep the script easier to maintain.
| $yml = @{ | |
| version = $version | |
| files = @( | |
| @{ | |
| url = $mainExe.Name | |
| sha512 = $null | |
| sha256 = $hash | |
| size = $size | |
| blockMapSize = $null | |
| } | |
| ) | |
| releaseDate = $releaseDate | |
| } |
| $signedExe = Get-ChildItem $buildDir -Recurse -Filter $zipExe.Name -ErrorAction SilentlyContinue | Select-Object -First 1 | ||
| if ($signedExe) { | ||
| Copy-Item $signedExe.FullName $zipExe.FullName -Force | ||
| Write-Host " Replaced $($zipExe.Name) with signed binary." | ||
| } else { | ||
| Write-Host " No signed match found for $($zipExe.Name)." | ||
| } | ||
| } | ||
|
|
||
| Remove-Item $zip.FullName -Force | ||
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force |
There was a problem hiding this comment.
Portable ZIP repack: the replacement EXE is chosen by name with Get-ChildItem ... -Recurse -Filter $zipExe.Name | Select-Object -First 1. If multiple EXEs share a name under build/ (common with unpacked directories), this can copy the wrong binary into the ZIP. Consider matching by expected relative path, verifying the candidate is Authenticode-signed before copying, and cleaning up $tempDir after repacking to avoid leaking temp directories.
| $signedExe = Get-ChildItem $buildDir -Recurse -Filter $zipExe.Name -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($signedExe) { | |
| Copy-Item $signedExe.FullName $zipExe.FullName -Force | |
| Write-Host " Replaced $($zipExe.Name) with signed binary." | |
| } else { | |
| Write-Host " No signed match found for $($zipExe.Name)." | |
| } | |
| } | |
| Remove-Item $zip.FullName -Force | |
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force | |
| # Prefer matching the EXE by its relative path within the ZIP | |
| $relativePath = $zipExe.FullName.Substring($tempDir.Length).TrimStart('\','/') | |
| $expectedSignedExePath = Join-Path $buildDir $relativePath | |
| $candidateExecutables = @() | |
| if (Test-Path $expectedSignedExePath) { | |
| $candidateExecutables += Get-Item $expectedSignedExePath | |
| } else { | |
| # Fallback: search by file name under the build directory (may return multiple matches) | |
| $candidateExecutables += Get-ChildItem $buildDir -Recurse -Filter $zipExe.Name -ErrorAction SilentlyContinue | |
| } | |
| $signedExe = $null | |
| foreach ($candidate in $candidateExecutables) { | |
| $signature = Get-AuthenticodeSignature -FilePath $candidate.FullName | |
| if ($signature.Status -eq 'Valid') { | |
| $signedExe = $candidate | |
| break | |
| } | |
| } | |
| if ($signedExe) { | |
| Copy-Item $signedExe.FullName $zipExe.FullName -Force | |
| Write-Host " Replaced $($zipExe.FullName.Substring($tempDir.Length).TrimStart('\','/')) with signed binary at $($signedExe.FullName)." | |
| } else { | |
| Write-Host " No valid signed match found for $($zipExe.FullName.Substring($tempDir.Length).TrimStart('\','/'))." | |
| } | |
| } | |
| Remove-Item $zip.FullName -Force | |
| Compress-Archive -Path (Join-Path $tempDir '*') -DestinationPath $zip.FullName -Force | |
| # Clean up temporary directory to avoid leaking temp artifacts | |
| Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue |
* Initial plan * Fix macOS notarization failures with timestamps and signing improvements Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Apply macOS notarization fixes to nightly build workflow Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * chore: add macOS certificate files to .gitignore * fix: update macOS code signing verification to skip spctl assessment * fix: enhance macOS notarization steps to support multiple artifacts and improve error handling * fix: update notarization scripts to support multiple asset types and improve error handling * fix: update version to 1.1.3 in package.json * feat: Associate browser profile with connections - visual tags and profile detection (#355) * Initial plan * Add browser profile support for interactive authentication - Add browserType and browserProfile fields to DataverseConnection interface - Implement browser-specific launch logic in AuthManager - Update add/edit connection modals with browser selection UI - Support Chrome, Edge, Firefox, and Brave browsers - Fallback to default browser if profile not found Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review feedback - use helper functions consistently Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Refactor: Extract browser logic into separate BrowserManager - Create new BrowserManager class for browser detection and profile enumeration - Remove browser-related code from AuthManager - AuthManager now depends on BrowserManager via constructor injection - Add IPC channels for browser detection and profile listing - Update preload script to expose new browser APIs Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Implement dynamic browser profile detection in UI - Replace text input with dropdown for browser profiles - Dynamically detect browser installation on selection - Automatically load and populate browser profiles - Show warning when selected browser is not installed - Support both add and edit connection modals - Add modal-warning CSS for user feedback Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix: Browser profile detection in modals - Expose browser detection APIs in modalPreload.ts - Fix browser type change event to properly trigger profile loading - Set correct initial state for profile dropdown (No profile needed) - Remove premature loadBrowserProfiles() call that ran before DOM ready Fixes: - Profile selector now loads data when browser is selected - Browser detection APIs now available in modal context - Initial dropdown state shows correct message - Warning displays when browser not installed Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Enhance profile detection to show friendly names, support Chrome/Edge only - Read actual profile names from Local State file (e.g., "Person 1", "Work") - Fallback to reading individual Preferences files if Local State unavailable - Remove Firefox and Brave browser support (Chrome and Edge only) - UI now displays profile.name but stores profile.path for --profile-directory - Update both add and edit connection modals Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Move browser settings to separate section available for all auth types - Move browser type and profile selectors out of interactive-only section - Create new "Browser Settings (Optional)" section below Environment selector - Apply browser settings to all authentication types (interactive, clientSecret, usernamePassword, connectionString) - Browser profile used when tools need to open URLs with authentication - Updated both add and edit connection modals - Updated connectionManagement to apply browser settings to all auth types Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fixed style issue and added logos * Add browser profile tag to connection cards in sidebar - Add browserProfileName field to DataverseConnection type - Display browser icon and profile name as tag on connection cards - Tag shows Chrome/Edge icon with friendly profile name (e.g., "My Cool Profile") - Tag positioned next to environment badge - Update form controllers to capture and store profile name - Add CSS styling for connection-browser-tag with browser icon - Browser icons loaded from renderer/icons/logos/ Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix modal hanging issue - improve browser profile name collection - Fix collectFormData to safely handle empty profile selections - Only capture browserProfileName when a profile is actually selected - Add null-safe checks for selectedOptions array access - Prevent attempting to read textContent from empty value options Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Revert "Fix modal hanging issue - improve browser profile name collection" This reverts commit 607fde9. * Revert "Add browser profile tag to connection cards in sidebar" This reverts commit e1cab02. * feat: add browser profile name support in connection forms and UI * Update src/renderer/modules/connectionManagement.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/main/managers/browserManager.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/main/managers/browserManager.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/common/types/connection.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add optional file type filters to saveFile with extension-based auto-derivation (#354) * Initial plan * Add optional filters parameter to saveFile function Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix extension extraction to use path.extname for robust handling Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com> * Signing executables for all platform (#377) * fix: enable recursive file search for notarization in release workflows * feat: add YAML regeneration steps for Windows, Linux, and macOS with correct SHA256 hashes * feat: add repackaging step for portable ZIP with signed EXE in Windows workflows * feat: Added support for Metadata CRUD operations (#356) * fix: Enhance Label structure compliance and add polymorphic lookup support This commit addresses documentation review findings and adds support for polymorphic lookup attributes (Customer/Regarding fields) to complete metadata CRUD operations implementation for issue #319. ## Type Definitions (src/common/types/dataverse.ts) - Added `IsManaged?: boolean` property to LocalizedLabel interface * Microsoft examples show IsManaged included in all attribute/relationship/optionset requests * Properly tracks whether label originates from managed solution - UserLocalizedLabel remains optional in Label interface * Entity creation docs note it as read-only * However, Microsoft's own examples for attributes, relationships, and optionsets include it in POST requests * Implementation follows Microsoft's published examples ## DataverseManager Updates (src/main/managers/dataverseManager.ts) - Updated buildLabel() helper method: * Now creates LocalizedLabel with IsManaged: false property * Includes UserLocalizedLabel property set to same LocalizedLabel instance * Matches Microsoft's published examples for attribute/relationship creation * Example output: { LocalizedLabels: [{ Label: "Text", LanguageCode: 1033, IsManaged: false }], UserLocalizedLabel: { Label: "Text", LanguageCode: 1033, IsManaged: false } } - Added createPolymorphicLookupAttribute() method: * Enables creation of lookup fields that reference multiple entity types (Customer, Regarding scenarios) * Validates presence of non-empty Targets array with entity logical names * Automatically sets AttributeType="Lookup" and AttributeTypeName={ Value: "LookupType" } * Delegates to createAttribute() with proper polymorphic configuration * Returns { AttributeId: string } matching API contract * Comprehensive JSDoc with Customer (account/contact) and custom Regarding examples - Enhanced createRelationship() JSDoc: * Added CascadeConfiguration example with all cascade behaviors (Assign, Delete, Merge, Reparent, Share, Unshare) * Shows proper RemoveLink delete behavior for lookup fields - Enhanced updateRelationship() JSDoc: * Added example demonstrating cascade configuration updates (RemoveLink → Cascade) * Illustrates retrieve-modify-PUT pattern for relationship updates - Added LocalizedLabel to imports from common types ## IPC Infrastructure (src/common/ipc/channels.ts, src/main/index.ts) - Added CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel constant * Value: "dataverse.createPolymorphicLookupAttribute" - Registered IPC handler in main process: * Supports both primary and secondary connection targets * Extracts connectionId from WebContents based on connectionTarget parameter * Wraps dataverseManager.createPolymorphicLookupAttribute() with error handling * Proper cleanup with removeHandler() on application quit ## Preload Bridge (src/main/toolPreloadBridge.ts) - Exposed createPolymorphicLookupAttribute in toolboxAPI.dataverse - Exposed createPolymorphicLookupAttribute in window.dataverseAPI - Both accept (entityLogicalName, attributeDefinition, options?, connectionTarget?) parameters - Properly wrapped with ipcInvoke using CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel ## Public API Types (packages/dataverseAPI.d.ts) - Added createPolymorphicLookupAttribute method signature to DataverseAPI interface - Comprehensive JSDoc documentation: * Customer lookup example (account/contact on new_order entity) * Multi-entity Regarding example (account/contact/custom entities on new_note) * Documents Targets array requirement * Notes metadata publish requirement * Shows buildLabel() usage in examples - Method signature: (entityLogicalName, attributeDefinition, options?, connectionTarget?) => Promise<{ AttributeId: string }> ## Validation - TypeScript compilation: ✅ No errors - ESLint: ✅ 0 errors (TypeScript version warning acceptable) - All 12 implementation tasks completed - Documentation compliance verified against 5 Microsoft Learn articles ## Microsoft Documentation References - Attribute creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-column-definitions-using-web-api - Relationship creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-relationships-using-web-api - Option sets: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-optionsets - Polymorphic lookups: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/multitable-lookup - Entity creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-definitions-using-web-api Closes #319 metadata CRUD operations (enhancement for polymorphic lookups) * fix: improve metadata CRUD error handling and add comprehensive documentation FIXES (Code Review Issues): 1. **Metadata creation methods now throw descriptive errors on missing headers** - createEntityDefinition, createAttribute, createRelationship, createGlobalOptionSet - Previously returned empty strings silently when OData-EntityId header missing - Now throw explicit errors: "Failed to retrieve MetadataId from response. The OData-EntityId header was missing." - Guides users to identify real issues (network failures, API changes, etc.) 2. **GET_ATTRIBUTE_ODATA_TYPE IPC handler now enforces type safety** - Added runtime enum validation against AttributeMetadataType values - Removed unsafe `as any` cast that bypassed TypeScript's type system - Throws descriptive error listing all valid types when invalid value provided - Example: "Invalid attribute type: 'InvalidType'. Valid types are: String, Integer, Boolean, ..." TECHNICAL DISCOVERY: **Dataverse metadata operations return HTTP 204 No Content with NO response body**: - Standard operations (entity, attribute, relationship, global option set): 204 No Content - Only OData-EntityId header contains the created MetadataId - Empty response body → makeHttpRequest returns `response.data = {}` - Exception: CreateCustomerRelationships action returns 200 OK with JSON body containing AttributeId and RelationshipIds This discovery led to abandoning a proposed "fallback to response body" approach, as responseData["MetadataId"] would always be undefined for metadata operations. DOCUMENTATION IMPROVEMENTS: 1. **execute() method**: Added comprehensive JSDoc with examples for: - CreateCustomerRelationships action (customer lookup creation with 200 OK response) - InsertStatusValue action (status choice column values with StateCode) - UpdateStateValue action (state value metadata updates) - Bound vs unbound actions/functions 2. **queryData() method**: Added examples demonstrating: - Retrieving global option sets by name: `GlobalOptionSetDefinitions(Name='name')` - Retrieving all global option sets with filters - Retrieving by MetadataId 3. **createPolymorphicLookupAttribute()**: Added note about CreateCustomerRelationships alternative 4. **insertOptionValue()**: Added note about InsertStatusValue for status choice columns 5. **createGlobalOptionSet()**: Added retrieval example using queryData() BENEFITS: - **Fail-Fast Approach**: Clear errors replace silent failures, improving debuggability - **Type Safety**: Runtime enum validation prevents invalid API calls - **Complete Coverage**: All metadata operations from Microsoft documentation are supported via existing methods (execute, queryData) - **Developer Guidance**: JSDoc examples show how to use actions like CreateCustomerRelationships, InsertStatusValue, UpdateStateValue - **No New Methods Needed**: Generic execute() and queryData() methods handle all special cases VALIDATION: - ✅ TypeScript compilation passed (pnpm run typecheck) - ✅ Linting passed (pnpm run lint - 0 errors) - ✅ Application builds successfully (pnpm build) - ✅ All 6 file edits applied successfully * feat(dataverse): add whitelist-based header validation for metadata operations Implemented comprehensive security validation for custom headers in metadata operations to prevent header injection attacks and API compliance issues. SECURITY ENHANCEMENTS: - Added validateMetadataHeaders() method with whitelist-based validation - Validates all custom headers against allowed list from Microsoft documentation - Blocks attempts to override protected headers (Authorization, Content-Type, etc.) - Case-insensitive header matching per HTTP specification (RFC 2616) - Detailed error messages showing invalid headers and allowed alternatives ALLOWED CUSTOM HEADERS (per Microsoft Dataverse Web API docs): - MSCRM.SolutionUniqueName: Associates metadata changes with solutions - MSCRM.MergeLabels: Controls label merging behavior (true/false) - Consistency: Forces reading latest version (value: "Strong") - If-Match: Standard HTTP header for optimistic concurrency control - If-None-Match: Standard HTTP header for caching control PROTECTED HEADERS (never allowed in customHeaders): - Authorization, Accept, Content-Type, OData-MaxVersion, OData-Version, Prefer, Content-Length (all controlled by makeHttpRequest) IMPLEMENTATION: - Created ALLOWED_METADATA_HEADERS constant with whitelist (5 headers) - Created PROTECTED_HEADERS constant with blacklist (7 headers) - Integrated validation into buildMetadataHeaders() for automatic coverage - All metadata operations now automatically validated: * createEntityDefinition / updateEntityDefinition * createAttribute / updateAttribute * createRelationship / updateRelationship * createGlobalOptionSet / updateGlobalOptionSet * createPolymorphicLookup BENEFITS: - Prevents header injection attacks and accidental header overrides - Ensures API compliance with Microsoft's documented patterns - Provides clear developer feedback when invalid headers are used - Defense-in-depth validation even for type-safe inputs DOCUMENTATION REFERENCES: Based on thorough review of 6 Microsoft Learn articles covering all metadata operation types (entity, attribute, relationship, option set operations). Changes maintain backward compatibility - all existing code uses valid headers through typed MetadataOperationOptions interface. * fix(types): replace 'any' with MetadataOperationOptions in IPC handlers Improved type safety in metadata operation IPC handlers by replacing all occurrences of 'options?: any' with proper 'options?: MetadataOperationOptions' type annotation. CHANGES: - Added MetadataOperationOptions to type imports from ../common/types - Updated 9 IPC handler signatures to use MetadataOperationOptions: * CREATE_ENTITY_DEFINITION * UPDATE_ENTITY_DEFINITION * CREATE_ATTRIBUTE * UPDATE_ATTRIBUTE * CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE * CREATE_RELATIONSHIP * UPDATE_RELATIONSHIP * CREATE_GLOBAL_OPTION_SET * UPDATE_GLOBAL_OPTION_SET BENEFITS: - Eliminates use of 'any' type, maintaining TypeScript strict mode compliance - Provides IntelliSense and autocomplete for options parameter - Type safety ensures only valid options (solutionUniqueName, mergeLabels, consistencyStrong) can be passed through IPC layer - Consistency with DataverseManager method signatures - Compile-time validation of option properties This change maintains backward compatibility while adding proper type checking for all metadata operation options passed from tools via IPC. * chore: update version to 1.0.19 in package.json * feat(preload): sync metadata CRUD operations with toolPreloadBridge Synchronized preload.ts with toolPreloadBridge.ts to ensure both the main ToolBox UI and tool windows have identical metadata operation APIs available. This maintains API parity and enables future metadata manipulation from the main UI if needed. ADDED METADATA OPERATIONS (22 new methods in dataverse namespace): Metadata Helper Utilities: - buildLabel: Build localized Label objects for metadata operations - getAttributeODataType: Get OData type string for attribute type enums Entity (Table) Metadata CRUD: - createEntityDefinition: Create new entity/table definitions - updateEntityDefinition: Update existing entity definitions (PUT) - deleteEntityDefinition: Delete entity definitions Attribute (Column) Metadata CRUD: - createAttribute: Create new attributes/columns on entities - updateAttribute: Update existing attribute definitions (PUT) - deleteAttribute: Delete attributes from entities - createPolymorphicLookupAttribute: Create multi-table lookup attributes Relationship Metadata CRUD: - createRelationship: Create 1:N, N:N, or polymorphic relationships - updateRelationship: Update existing relationship definitions (PUT) - deleteRelationship: Delete relationships Global Option Set (Choice) Metadata CRUD: - createGlobalOptionSet: Create new global option sets/choices - updateGlobalOptionSet: Update existing global option sets (PUT) - deleteGlobalOptionSet: Delete global option sets Option Value Modification Actions (OData Actions): - insertOptionValue: Insert new option values into option sets - updateOptionValue: Update existing option values (labels, etc.) - deleteOptionValue: Delete option values from option sets - orderOption: Reorder option values within option sets BENEFITS: - API parity between main UI (preload.ts) and tool windows (toolPreloadBridge.ts) - Main ToolBox UI can now perform metadata operations if needed in future - Consistent API surface across all preload contexts - Future-proofing for internal metadata management UI features - All operations support primary/secondary connection targeting IMPLEMENTATION NOTES: - All methods maintain same signatures as toolPreloadBridge.ts - Options parameter uses Record<string, unknown> for flexibility - Connection targeting via optional connectionTarget parameter - Validated header whitelisting enforced by DataverseManager layer This synchronization ensures both contexts stay in sync as the metadata API evolves and provides maximum flexibility for future UI enhancements. --------- Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com> * Fix loading overlay positioning and add manual dismiss button (#379) * Initial plan * Fix loading screen to only block tool panel, not entire window Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review: Fix listener leak and simplify null coalescing Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix IPC listener cleanup: use ipcMain.on instead of once Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix loading overlay bounds calculation and add close button - Get bounds directly from active tool BrowserView instead of renderer - Add getActiveToolBounds() method to ToolWindowManager - Remove rounded corners from overlay container - Add close button to manually dismiss loading overlay - Make overlay window focusable and closable Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Improve close button accessibility and contrast - Add aria-label for screen reader support - Increase background opacity for better contrast (0.1 -> 0.15) - Add visible focus indicator with blue border and shadow - Improve border visibility (0.2 -> 0.3 opacity) Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix overlay positioning and explicitly remove all rounded corners - Use content bounds (screen coordinates) instead of incorrectly adding window bounds to BrowserView bounds - Explicitly set border-radius:0 on overlay-container and close-button - BrowserView bounds are content-relative, overlay BrowserWindow needs screen coordinates Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review feedback: fix shutdown handling, HTML escaping, and error telemetry - Add isMainWindowClosing flag to allow overlay to close during app shutdown - Escape HTML in loading message to prevent injection attacks - Improve error handling with captureException and full context (activeToolId, tags) - Properly destroy overlay window in cleanup - Add close listener on main window to set shutdown flag Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Refine code review fixes: use specific listener reference and clarify HTML escaping - Store closeHandler reference to remove specific listener (not all listeners) - Add comment explaining critical order of HTML entity replacements - Prevent potential issues with removeAllListeners affecting other code Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Polish destroy logic for better clarity and consistency - Move overlayWindow null assignment inside if block for logical consistency - Set closeHandler to null after cleanup for better flow - Clearer separation of window cleanup vs handler cleanup Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * fix: update release date formatting in workflows for consistency (#383) * fix: clean up toolboxAPI type definitions and improve connection handling (#387) * feat: add getCSDLDocument API for retrieving OData endpoint (#384) (#385) * feat: add getCSDLDocument API for retrieving OData endpoint (#384) Add new getCSDLDocument() method to DataverseAPI that retrieves the complete CSDL/EDMX metadata document from Dataverse's OData $metadata endpoint. Key Features: - Returns raw XML containing complete schema metadata (entities, attributes, relationships, actions, functions, complex types, enum types) - Supports gzip/deflate compression for optimal transfer (70-80% size reduction) - Automatic decompression handling using Node.js zlib module - Multi-connection support (primary/secondary) for advanced tools - Response size: 1-5MB typical, up to 10MB+ for complex environments Implementation: - Added GET_CSDL_DOCUMENT IPC channel to channels.ts - Implemented getCSDLDocument() in DataverseManager with: - Custom HTTPS request handler (avoids JSON parsing) - Accept-Encoding: gzip, deflate headers - Automatic decompression via zlib.gunzip/inflate - Buffer-based response handling for binary data - Registered IPC handler in index.ts with connection targeting support - Exposed method in toolPreloadBridge.ts and preload.ts - Added comprehensive TypeScript definitions in dataverseAPI.d.ts Use Cases: - Build Dataverse REST Builder (DRB) clone tools - Create intelligent query builders and code generators - Generate TypeScript interfaces from schema - Explore entity relationships and metadata - Validate action/function parameters Naming Rationale: Method named getCSDLDocument() (not getMetadata()) to avoid confusion with existing entity metadata operations like getEntityMetadata() and getAllEntitiesMetadata(). CSDL (Common Schema Definition Language) clearly indicates it returns the OData service document. Related: #384 * fix: expose getCSDLDocument on window.dataverseAPI for direct tool access Fixed issue where getCSDLDocument was only accessible via window.toolboxAPI.dataverse.getCSDLDocument but not directly on window.dataverseAPI.getCSDLDocument like other Dataverse operations. Changes: - Added getCSDLDocument to toolPreloadBridge.ts dataverseAPI namespace - Now consistent with other operations (getSolutions, queryData, etc.) - Tools can call dataverseAPI.getCSDLDocument() directly as expected This ensures getCSDLDocument follows the same exposure pattern as all other Dataverse API methods. * fix: decompress error responses in getCSDLDocument for readable error messages Previously, error responses (non-200 status codes) were converted directly from Buffer to UTF-8 string without checking for compression. Since the request includes 'Accept-Encoding: gzip, deflate' header, Dataverse may return compressed error responses, resulting in garbled error messages. Changes: - Added decompression logic to error response path - Check content-encoding header (gzip/deflate/none) - Decompress error body before converting to string - Added try-catch to handle decompression failures gracefully - Error messages now readable regardless of compression This mirrors the success path's decompression logic and ensures consistent handling of both success and error responses. * File System cleanup (#389) * fix: clean up toolboxAPI type definitions and improve connection handling * fix: implement filesystem access management for tools with user consent model * Fix filesystem access tracking to use instanceId instead of toolId (#390) * Initial plan * fix: track filesystem access per instance instead of per tool This change fixes the issue where closing one instance of a tool would revoke filesystem access for all other instances of the same tool. Changes: - Updated ToolFileSystemAccessManager to use instanceId as key instead of toolId - Added getInstanceIdByWebContents() method to ToolWindowManager - Updated all filesystem IPC handlers to use instanceId - Updated closeTool() to revoke access only for the specific instance This ensures that each tool instance maintains its own filesystem permissions independently, allowing multiple instances of the same tool to run simultaneously without interfering with each other. Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * refactor: eliminate code duplication in toolWindowManager methods Refactor getToolIdByWebContents() to call getInstanceIdByWebContents() and extract the toolId from the result, eliminating duplicated loop logic. Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> * fix: update force check-in timestamp in README.md * fix: calculate and log SHA256 and SHA512 hashes in release workflows * chore: update RELEASE_NOTES.md for version 1.1.3 with highlights and fixes --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: mohsinonxrm <mohsinonxrm@outlook.com>
* Initial plan
* Fix macOS notarization failures with timestamps and signing improvements
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply macOS notarization fixes to nightly build workflow
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* chore: add macOS certificate files to .gitignore
* fix: update macOS code signing verification to skip spctl assessment
* fix: enhance macOS notarization steps to support multiple artifacts and improve error handling
* fix: update notarization scripts to support multiple asset types and improve error handling
* fix: update version to 1.1.3 in package.json
* feat: Associate browser profile with connections - visual tags and profile detection (#355)
* Initial plan
* Add browser profile support for interactive authentication
- Add browserType and browserProfile fields to DataverseConnection interface
- Implement browser-specific launch logic in AuthManager
- Update add/edit connection modals with browser selection UI
- Support Chrome, Edge, Firefox, and Brave browsers
- Fallback to default browser if profile not found
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback - use helper functions consistently
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Refactor: Extract browser logic into separate BrowserManager
- Create new BrowserManager class for browser detection and profile enumeration
- Remove browser-related code from AuthManager
- AuthManager now depends on BrowserManager via constructor injection
- Add IPC channels for browser detection and profile listing
- Update preload script to expose new browser APIs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Implement dynamic browser profile detection in UI
- Replace text input with dropdown for browser profiles
- Dynamically detect browser installation on selection
- Automatically load and populate browser profiles
- Show warning when selected browser is not installed
- Support both add and edit connection modals
- Add modal-warning CSS for user feedback
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix: Browser profile detection in modals
- Expose browser detection APIs in modalPreload.ts
- Fix browser type change event to properly trigger profile loading
- Set correct initial state for profile dropdown (No profile needed)
- Remove premature loadBrowserProfiles() call that ran before DOM ready
Fixes:
- Profile selector now loads data when browser is selected
- Browser detection APIs now available in modal context
- Initial dropdown state shows correct message
- Warning displays when browser not installed
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Enhance profile detection to show friendly names, support Chrome/Edge only
- Read actual profile names from Local State file (e.g., "Person 1", "Work")
- Fallback to reading individual Preferences files if Local State unavailable
- Remove Firefox and Brave browser support (Chrome and Edge only)
- UI now displays profile.name but stores profile.path for --profile-directory
- Update both add and edit connection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Move browser settings to separate section available for all auth types
- Move browser type and profile selectors out of interactive-only section
- Create new "Browser Settings (Optional)" section below Environment selector
- Apply browser settings to all authentication types (interactive, clientSecret, usernamePassword, connectionString)
- Browser profile used when tools need to open URLs with authentication
- Updated both add and edit connection modals
- Updated connectionManagement to apply browser settings to all auth types
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fixed style issue and added logos
* Add browser profile tag to connection cards in sidebar
- Add browserProfileName field to DataverseConnection type
- Display browser icon and profile name as tag on connection cards
- Tag shows Chrome/Edge icon with friendly profile name (e.g., "My Cool Profile")
- Tag positioned next to environment badge
- Update form controllers to capture and store profile name
- Add CSS styling for connection-browser-tag with browser icon
- Browser icons loaded from renderer/icons/logos/
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix modal hanging issue - improve browser profile name collection
- Fix collectFormData to safely handle empty profile selections
- Only capture browserProfileName when a profile is actually selected
- Add null-safe checks for selectedOptions array access
- Prevent attempting to read textContent from empty value options
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Revert "Fix modal hanging issue - improve browser profile name collection"
This reverts commit 607fde9bdc171cdaf3039153d6457ff8a3c4d814.
* Revert "Add browser profile tag to connection cards in sidebar"
This reverts commit e1cab02dfd7401b5555de63bee6e664eea96e4d8.
* feat: add browser profile name support in connection forms and UI
* Update src/renderer/modules/connectionManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/browserManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/browserManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/common/types/connection.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add optional file type filters to saveFile with extension-based auto-derivation (#354)
* Initial plan
* Add optional filters parameter to saveFile function
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix extension extraction to use path.extname for robust handling
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Signing executables for all platform (#377)
* fix: enable recursive file search for notarization in release workflows
* feat: add YAML regeneration steps for Windows, Linux, and macOS with correct SHA256 hashes
* feat: add repackaging step for portable ZIP with signed EXE in Windows workflows
* feat: Added support for Metadata CRUD operations (#356)
* fix: Enhance Label structure compliance and add polymorphic lookup support
This commit addresses documentation review findings and adds support for polymorphic lookup attributes (Customer/Regarding fields) to complete metadata CRUD operations implementation for issue #319.
## Type Definitions (src/common/types/dataverse.ts)
- Added `IsManaged?: boolean` property to LocalizedLabel interface
* Microsoft examples show IsManaged included in all attribute/relationship/optionset requests
* Properly tracks whether label originates from managed solution
- UserLocalizedLabel remains optional in Label interface
* Entity creation docs note it as read-only
* However, Microsoft's own examples for attributes, relationships, and optionsets include it in POST requests
* Implementation follows Microsoft's published examples
## DataverseManager Updates (src/main/managers/dataverseManager.ts)
- Updated buildLabel() helper method:
* Now creates LocalizedLabel with IsManaged: false property
* Includes UserLocalizedLabel property set to same LocalizedLabel instance
* Matches Microsoft's published examples for attribute/relationship creation
* Example output: { LocalizedLabels: [{ Label: "Text", LanguageCode: 1033, IsManaged: false }], UserLocalizedLabel: { Label: "Text", LanguageCode: 1033, IsManaged: false } }
- Added createPolymorphicLookupAttribute() method:
* Enables creation of lookup fields that reference multiple entity types (Customer, Regarding scenarios)
* Validates presence of non-empty Targets array with entity logical names
* Automatically sets AttributeType="Lookup" and AttributeTypeName={ Value: "LookupType" }
* Delegates to createAttribute() with proper polymorphic configuration
* Returns { AttributeId: string } matching API contract
* Comprehensive JSDoc with Customer (account/contact) and custom Regarding examples
- Enhanced createRelationship() JSDoc:
* Added CascadeConfiguration example with all cascade behaviors (Assign, Delete, Merge, Reparent, Share, Unshare)
* Shows proper RemoveLink delete behavior for lookup fields
- Enhanced updateRelationship() JSDoc:
* Added example demonstrating cascade configuration updates (RemoveLink → Cascade)
* Illustrates retrieve-modify-PUT pattern for relationship updates
- Added LocalizedLabel to imports from common types
## IPC Infrastructure (src/common/ipc/channels.ts, src/main/index.ts)
- Added CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel constant
* Value: "dataverse.createPolymorphicLookupAttribute"
- Registered IPC handler in main process:
* Supports both primary and secondary connection targets
* Extracts connectionId from WebContents based on connectionTarget parameter
* Wraps dataverseManager.createPolymorphicLookupAttribute() with error handling
* Proper cleanup with removeHandler() on application quit
## Preload Bridge (src/main/toolPreloadBridge.ts)
- Exposed createPolymorphicLookupAttribute in toolboxAPI.dataverse
- Exposed createPolymorphicLookupAttribute in window.dataverseAPI
- Both accept (entityLogicalName, attributeDefinition, options?, connectionTarget?) parameters
- Properly wrapped with ipcInvoke using CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel
## Public API Types (packages/dataverseAPI.d.ts)
- Added createPolymorphicLookupAttribute method signature to DataverseAPI interface
- Comprehensive JSDoc documentation:
* Customer lookup example (account/contact on new_order entity)
* Multi-entity Regarding example (account/contact/custom entities on new_note)
* Documents Targets array requirement
* Notes metadata publish requirement
* Shows buildLabel() usage in examples
- Method signature: (entityLogicalName, attributeDefinition, options?, connectionTarget?) => Promise<{ AttributeId: string }>
## Validation
- TypeScript compilation: ✅ No errors
- ESLint: ✅ 0 errors (TypeScript version warning acceptable)
- All 12 implementation tasks completed
- Documentation compliance verified against 5 Microsoft Learn articles
## Microsoft Documentation References
- Attribute creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-column-definitions-using-web-api
- Relationship creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-relationships-using-web-api
- Option sets: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-optionsets
- Polymorphic lookups: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/multitable-lookup
- Entity creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-definitions-using-web-api
Closes #319 metadata CRUD operations (enhancement for polymorphic lookups)
* fix: improve metadata CRUD error handling and add comprehensive documentation
FIXES (Code Review Issues):
1. **Metadata creation methods now throw descriptive errors on missing headers**
- createEntityDefinition, createAttribute, createRelationship, createGlobalOptionSet
- Previously returned empty strings silently when OData-EntityId header missing
- Now throw explicit errors: "Failed to retrieve MetadataId from response. The OData-EntityId header was missing."
- Guides users to identify real issues (network failures, API changes, etc.)
2. **GET_ATTRIBUTE_ODATA_TYPE IPC handler now enforces type safety**
- Added runtime enum validation against AttributeMetadataType values
- Removed unsafe `as any` cast that bypassed TypeScript's type system
- Throws descriptive error listing all valid types when invalid value provided
- Example: "Invalid attribute type: 'InvalidType'. Valid types are: String, Integer, Boolean, ..."
TECHNICAL DISCOVERY:
**Dataverse metadata operations return HTTP 204 No Content with NO response body**:
- Standard operations (entity, attribute, relationship, global option set): 204 No Content
- Only OData-EntityId header contains the created MetadataId
- Empty response body → makeHttpRequest returns `response.data = {}`
- Exception: CreateCustomerRelationships action returns 200 OK with JSON body containing AttributeId and RelationshipIds
This discovery led to abandoning a proposed "fallback to response body" approach, as responseData["MetadataId"] would always be undefined for metadata operations.
DOCUMENTATION IMPROVEMENTS:
1. **execute() method**: Added comprehensive JSDoc with examples for:
- CreateCustomerRelationships action (customer lookup creation with 200 OK response)
- InsertStatusValue action (status choice column values with StateCode)
- UpdateStateValue action (state value metadata updates)
- Bound vs unbound actions/functions
2. **queryData() method**: Added examples demonstrating:
- Retrieving global option sets by name: `GlobalOptionSetDefinitions(Name='name')`
- Retrieving all global option sets with filters
- Retrieving by MetadataId
3. **createPolymorphicLookupAttribute()**: Added note about CreateCustomerRelationships alternative
4. **insertOptionValue()**: Added note about InsertStatusValue for status choice columns
5. **createGlobalOptionSet()**: Added retrieval example using queryData()
BENEFITS:
- **Fail-Fast Approach**: Clear errors replace silent failures, improving debuggability
- **Type Safety**: Runtime enum validation prevents invalid API calls
- **Complete Coverage**: All metadata operations from Microsoft documentation are supported via existing methods (execute, queryData)
- **Developer Guidance**: JSDoc examples show how to use actions like CreateCustomerRelationships, InsertStatusValue, UpdateStateValue
- **No New Methods Needed**: Generic execute() and queryData() methods handle all special cases
VALIDATION:
- ✅ TypeScript compilation passed (pnpm run typecheck)
- ✅ Linting passed (pnpm run lint - 0 errors)
- ✅ Application builds successfully (pnpm build)
- ✅ All 6 file edits applied successfully
* feat(dataverse): add whitelist-based header validation for metadata operations
Implemented comprehensive security validation for custom headers in metadata
operations to prevent header injection attacks and API compliance issues.
SECURITY ENHANCEMENTS:
- Added validateMetadataHeaders() method with whitelist-based validation
- Validates all custom headers against allowed list from Microsoft documentation
- Blocks attempts to override protected headers (Authorization, Content-Type, etc.)
- Case-insensitive header matching per HTTP specification (RFC 2616)
- Detailed error messages showing invalid headers and allowed alternatives
ALLOWED CUSTOM HEADERS (per Microsoft Dataverse Web API docs):
- MSCRM.SolutionUniqueName: Associates metadata changes with solutions
- MSCRM.MergeLabels: Controls label merging behavior (true/false)
- Consistency: Forces reading latest version (value: "Strong")
- If-Match: Standard HTTP header for optimistic concurrency control
- If-None-Match: Standard HTTP header for caching control
PROTECTED HEADERS (never allowed in customHeaders):
- Authorization, Accept, Content-Type, OData-MaxVersion, OData-Version,
Prefer, Content-Length (all controlled by makeHttpRequest)
IMPLEMENTATION:
- Created ALLOWED_METADATA_HEADERS constant with whitelist (5 headers)
- Created PROTECTED_HEADERS constant with blacklist (7 headers)
- Integrated validation into buildMetadataHeaders() for automatic coverage
- All metadata operations now automatically validated:
* createEntityDefinition / updateEntityDefinition
* createAttribute / updateAttribute
* createRelationship / updateRelationship
* createGlobalOptionSet / updateGlobalOptionSet
* createPolymorphicLookup
BENEFITS:
- Prevents header injection attacks and accidental header overrides
- Ensures API compliance with Microsoft's documented patterns
- Provides clear developer feedback when invalid headers are used
- Defense-in-depth validation even for type-safe inputs
DOCUMENTATION REFERENCES:
Based on thorough review of 6 Microsoft Learn articles covering all metadata
operation types (entity, attribute, relationship, option set operations).
Changes maintain backward compatibility - all existing code uses valid headers
through typed MetadataOperationOptions interface.
* fix(types): replace 'any' with MetadataOperationOptions in IPC handlers
Improved type safety in metadata operation IPC handlers by replacing all
occurrences of 'options?: any' with proper 'options?: MetadataOperationOptions'
type annotation.
CHANGES:
- Added MetadataOperationOptions to type imports from ../common/types
- Updated 9 IPC handler signatures to use MetadataOperationOptions:
* CREATE_ENTITY_DEFINITION
* UPDATE_ENTITY_DEFINITION
* CREATE_ATTRIBUTE
* UPDATE_ATTRIBUTE
* CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE
* CREATE_RELATIONSHIP
* UPDATE_RELATIONSHIP
* CREATE_GLOBAL_OPTION_SET
* UPDATE_GLOBAL_OPTION_SET
BENEFITS:
- Eliminates use of 'any' type, maintaining TypeScript strict mode compliance
- Provides IntelliSense and autocomplete for options parameter
- Type safety ensures only valid options (solutionUniqueName, mergeLabels,
consistencyStrong) can be passed through IPC layer
- Consistency with DataverseManager method signatures
- Compile-time validation of option properties
This change maintains backward compatibility while adding proper type checking
for all metadata operation options passed from tools via IPC.
* chore: update version to 1.0.19 in package.json
* feat(preload): sync metadata CRUD operations with toolPreloadBridge
Synchronized preload.ts with toolPreloadBridge.ts to ensure both the main
ToolBox UI and tool windows have identical metadata operation APIs available.
This maintains API parity and enables future metadata manipulation from the
main UI if needed.
ADDED METADATA OPERATIONS (22 new methods in dataverse namespace):
Metadata Helper Utilities:
- buildLabel: Build localized Label objects for metadata operations
- getAttributeODataType: Get OData type string for attribute type enums
Entity (Table) Metadata CRUD:
- createEntityDefinition: Create new entity/table definitions
- updateEntityDefinition: Update existing entity definitions (PUT)
- deleteEntityDefinition: Delete entity definitions
Attribute (Column) Metadata CRUD:
- createAttribute: Create new attributes/columns on entities
- updateAttribute: Update existing attribute definitions (PUT)
- deleteAttribute: Delete attributes from entities
- createPolymorphicLookupAttribute: Create multi-table lookup attributes
Relationship Metadata CRUD:
- createRelationship: Create 1:N, N:N, or polymorphic relationships
- updateRelationship: Update existing relationship definitions (PUT)
- deleteRelationship: Delete relationships
Global Option Set (Choice) Metadata CRUD:
- createGlobalOptionSet: Create new global option sets/choices
- updateGlobalOptionSet: Update existing global option sets (PUT)
- deleteGlobalOptionSet: Delete global option sets
Option Value Modification Actions (OData Actions):
- insertOptionValue: Insert new option values into option sets
- updateOptionValue: Update existing option values (labels, etc.)
- deleteOptionValue: Delete option values from option sets
- orderOption: Reorder option values within option sets
BENEFITS:
- API parity between main UI (preload.ts) and tool windows (toolPreloadBridge.ts)
- Main ToolBox UI can now perform metadata operations if needed in future
- Consistent API surface across all preload contexts
- Future-proofing for internal metadata management UI features
- All operations support primary/secondary connection targeting
IMPLEMENTATION NOTES:
- All methods maintain same signatures as toolPreloadBridge.ts
- Options parameter uses Record<string, unknown> for flexibility
- Connection targeting via optional connectionTarget parameter
- Validated header whitelisting enforced by DataverseManager layer
This synchronization ensures both contexts stay in sync as the metadata API
evolves and provides maximum flexibility for future UI enhancements.
---------
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Fix loading overlay positioning and add manual dismiss button (#379)
* Initial plan
* Fix loading screen to only block tool panel, not entire window
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review: Fix listener leak and simplify null coalescing
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix IPC listener cleanup: use ipcMain.on instead of once
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix loading overlay bounds calculation and add close button
- Get bounds directly from active tool BrowserView instead of renderer
- Add getActiveToolBounds() method to ToolWindowManager
- Remove rounded corners from overlay container
- Add close button to manually dismiss loading overlay
- Make overlay window focusable and closable
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Improve close button accessibility and contrast
- Add aria-label for screen reader support
- Increase background opacity for better contrast (0.1 -> 0.15)
- Add visible focus indicator with blue border and shadow
- Improve border visibility (0.2 -> 0.3 opacity)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix overlay positioning and explicitly remove all rounded corners
- Use content bounds (screen coordinates) instead of incorrectly adding window bounds to BrowserView bounds
- Explicitly set border-radius:0 on overlay-container and close-button
- BrowserView bounds are content-relative, overlay BrowserWindow needs screen coordinates
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback: fix shutdown handling, HTML escaping, and error telemetry
- Add isMainWindowClosing flag to allow overlay to close during app shutdown
- Escape HTML in loading message to prevent injection attacks
- Improve error handling with captureException and full context (activeToolId, tags)
- Properly destroy overlay window in cleanup
- Add close listener on main window to set shutdown flag
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Refine code review fixes: use specific listener reference and clarify HTML escaping
- Store closeHandler reference to remove specific listener (not all listeners)
- Add comment explaining critical order of HTML entity replacements
- Prevent potential issues with removeAllListeners affecting other code
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Polish destroy logic for better clarity and consistency
- Move overlayWindow null assignment inside if block for logical consistency
- Set closeHandler to null after cleanup for better flow
- Clearer separation of window cleanup vs handler cleanup
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update release date formatting in workflows for consistency (#383)
* fix: clean up toolboxAPI type definitions and improve connection handling (#387)
* feat: add getCSDLDocument API for retrieving OData endpoint (#384) (#385)
* feat: add getCSDLDocument API for retrieving OData endpoint (#384)
Add new getCSDLDocument() method to DataverseAPI that retrieves the complete
CSDL/EDMX metadata document from Dataverse's OData $metadata endpoint.
Key Features:
- Returns raw XML containing complete schema metadata (entities, attributes,
relationships, actions, functions, complex types, enum types)
- Supports gzip/deflate compression for optimal transfer (70-80% size reduction)
- Automatic decompression handling using Node.js zlib module
- Multi-connection support (primary/secondary) for advanced tools
- Response size: 1-5MB typical, up to 10MB+ for complex environments
Implementation:
- Added GET_CSDL_DOCUMENT IPC channel to channels.ts
- Implemented getCSDLDocument() in DataverseManager with:
- Custom HTTPS request handler (avoids JSON parsing)
- Accept-Encoding: gzip, deflate headers
- Automatic decompression via zlib.gunzip/inflate
- Buffer-based response handling for binary data
- Registered IPC handler in index.ts with connection targeting support
- Exposed method in toolPreloadBridge.ts and preload.ts
- Added comprehensive TypeScript definitions in dataverseAPI.d.ts
Use Cases:
- Build Dataverse REST Builder (DRB) clone tools
- Create intelligent query builders and code generators
- Generate TypeScript interfaces from schema
- Explore entity relationships and metadata
- Validate action/function parameters
Naming Rationale:
Method named getCSDLDocument() (not getMetadata()) to avoid confusion with
existing entity metadata operations like getEntityMetadata() and
getAllEntitiesMetadata(). CSDL (Common Schema Definition Language) clearly
indicates it returns the OData service document.
Related: #384
* fix: expose getCSDLDocument on window.dataverseAPI for direct tool access
Fixed issue where getCSDLDocument was only accessible via
window.toolboxAPI.dataverse.getCSDLDocument but not directly on
window.dataverseAPI.getCSDLDocument like other Dataverse operations.
Changes:
- Added getCSDLDocument to toolPreloadBridge.ts dataverseAPI namespace
- Now consistent with other operations (getSolutions, queryData, etc.)
- Tools can call dataverseAPI.getCSDLDocument() directly as expected
This ensures getCSDLDocument follows the same exposure pattern as all
other Dataverse API methods.
* fix: decompress error responses in getCSDLDocument for readable error messages
Previously, error responses (non-200 status codes) were converted directly
from Buffer to UTF-8 string without checking for compression. Since the
request includes 'Accept-Encoding: gzip, deflate' header, Dataverse may
return compressed error responses, resulting in garbled error messages.
Changes:
- Added decompression logic to error response path
- Check content-encoding header (gzip/deflate/none)
- Decompress error body before converting to string
- Added try-catch to handle decompression failures gracefully
- Error messages now readable regardless of compression
This mirrors the success path's decompression logic and ensures consistent
handling of both success and error responses.
* File System cleanup (#389)
* fix: clean up toolboxAPI type definitions and improve connection handling
* fix: implement filesystem access management for tools with user consent model
* Fix filesystem access tracking to use instanceId instead of toolId (#390)
* Initial plan
* fix: track filesystem access per instance instead of per tool
This change fixes the issue where closing one instance of a tool would
revoke filesystem access for all other instances of the same tool.
Changes:
- Updated ToolFileSystemAccessManager to use instanceId as key instead of toolId
- Added getInstanceIdByWebContents() method to ToolWindowManager
- Updated all filesystem IPC handlers to use instanceId
- Updated closeTool() to revoke access only for the specific instance
This ensures that each tool instance maintains its own filesystem
permissions independently, allowing multiple instances of the same tool
to run simultaneously without interfering with each other.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* refactor: eliminate code duplication in toolWindowManager methods
Refactor getToolIdByWebContents() to call getInstanceIdByWebContents()
and extract the toolId from the result, eliminating duplicated loop logic.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* fix: update force check-in timestamp in README.md
* fix: calculate and log SHA256 and SHA512 hashes in release workflows
* chore: update RELEASE_NOTES.md for version 1.1.3 with highlights and fixes
* fix: update version to 1.0.20 in package.json
* Fix Windows and macOS auto-update downloading wrong architecture installer (#397)
* Initial plan
* Add Windows multi-architecture support to latest.yml generation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply Windows YAML merge fix to nightly-release workflow
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add standalone script to generate merged Windows latest.yml
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add buildScripts/latest.yml to gitignore and remove example file
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add macOS multi-architecture support to latest-mac.yml generation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove legacy build scripts and add new merge scripts for Windows and macOS
- Deleted old merge scripts: merge-macos-latest-yml.sh, merge-windows-latest-yml.sh, test-macos-build.sh, verify-build.sh
- Added new merge scripts for Windows and macOS with improved functionality and documentation.
- Created README for merge scripts detailing usage and troubleshooting.
- Implemented new test and verification scripts for macOS builds to ensure proper packaging and structure.
* fix: correct path to verify-build.sh script in build workflow
* Update buildScripts/sh/merge-latest-yml.sh
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update .github/workflows/prod-release.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update .github/workflows/nightly-release.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update macOS release scripts to use ZIP artifacts instead of DMG files
* fix: add webresource to entity mapping in DataverseManager (#402)
* Move marketplace to azure blob (#403)
* Add support for bundled SVG icons in tools with backward compatibility (#380)
* Initial plan
* Add SVG icon support with pptb-webview protocol for bundled icons
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback: fix recent tools icon handling and add HTML escaping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive HTML escaping for XSS prevention in icon URLs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Improve accessibility and eliminate code duplication in HTML escaping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add defensive URL validation to prevent JavaScript protocol injection
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix CodeQL warning by blocking vbscript protocol in URL validation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove HTTP(S) icon support, change path to dist/ relative, rename iconUrl to icon
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update ToolManifest comment to reflect bundled icons only (no HTTP URLs)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add support for new Supabase 'icon' column with backward compatibility fallback to 'iconurl'
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix CSP error by allowing HTTP(S) URLs for marketplace icon display
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add pptb-webview protocol to CSP img-src to allow local SVG icon loading
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: add SVG icon support and improve icon URL resolution
* feat: implement theme-aware SVG icon support with CSS masks and improve icon rendering
* refactor: remove tool icon configuration section from README.md
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Move tool distribution from GitHub Releases to Azure Blob Storage (#400)
* Initial plan
* Add Azure Blob Storage support for tool distribution and registry fallback
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove hard-coded Azure Blob storage account name; resolve URLs at runtime from AZURE_BLOB_BASE_URL
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Simplify registry.json downloadUrl to filename-only; packages/ prefix added automatically at runtime
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Use per-tool version folder layout in Azure Blob, mirroring GitHub Releases structure
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Read download URL from new 'download' column in Supabase tools table, fall back to 'downloadurl'
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update Azure Blob Storage migration documentation to reflect new package structure
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* feat: enhance ToolManager to create tools from installed manifests and improve tool retrieval logic
* Update src/main/constants.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Azure Blob test download URL to dedicated test path (#404)
* Initial plan
* Update test tool download URL to /test/pptb-standard-sample-tool-download-test.tar.gz
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix resolveDownloadUrl to include packages/ prefix for Azure Blob Storage paths (#405)
* Initial plan
* fix: include packages/ prefix in resolveDownloadUrl for Azure Blob Storage
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix: include `icon` field in `fetchAzureBlobRegistry` tool mapping (#406)
* Initial plan
* fix: include icon field in fetchAzureBlobRegistry mapping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/main/index.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update version to 1.2.0 in package.json
* Replace native OS update dialogs with themed custom modal (#408)
* Initial plan
* Add modern themed update notification modal dialog
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address review comments: reword restart warning and extract highlights from release notes
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/renderer/modules/autoUpdateManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add global search command palette to activity bar (#409)
* Initial plan
* Add global search command palette to activity bar
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Enhance global search: launch tools, show marketplace detail, focus settings
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/renderer/index.html
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Improve tool load time (#410)
* Improve tool load time
* Update src/renderer/index.html
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add tool version compatibility checking with proper cache management (#378)
* Initial plan
* Add version compatibility types and backend logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add UI components for tool version compatibility
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add GitHub workflow steps for version sync and @pptb/types publishing
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive documentation for tool version compatibility feature
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add implementation checklist for version compatibility feature
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix code review issues: improve version comparison and validation logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix documentation to match corrected implementation logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix compatibility logic to support forward compatibility as requested
- Remove maxAPI restriction - tools built with older APIs work on newer ToolBox
- Add MIN_SUPPORTED_API_VERSION check to prevent tools using deprecated APIs
- Update documentation with correct examples matching user's requirements
- Tool with minAPI="1.0.0", maxAPI="1.0.4" now works on ToolBox v1.0.5
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* docs: enhance TOOL_VERSION_COMPATIBILITY.md with clearer formatting and examples for version checks
* Refactor version logic into VersionManager and correct data flow
- Create new VersionManager class to handle all version comparison and compatibility checking
- Move compareVersions and isToolSupported functions from toolsManager to VersionManager
- Update toolRegistryManager to only read version info from Supabase (not from package.json/npm-shrinkwrap)
- Version data (min_api, max_api) is now pre-processed during tool intake and stored in database
- Update documentation to reflect corrected data flow
- toolsManager now uses VersionManager.isToolSupported() for compatibility checks
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Use app.getVersion() instead of TOOLBOX_VERSION constant and create reusable npm publish workflow
- Replace TOOLBOX_VERSION constant with app.getVersion() call in VersionManager
- Remove TOOLBOX_VERSION from constants.ts and vite.config.ts
- Create standalone publish-npm-types.yml workflow with trusted publishing support
- Update prod-release.yml to use reusable workflow for npm publishing
- Update nightly-release.yml to use reusable workflow for npm beta publishing
- Add id-token: write permission for npm trusted publishing
- Add --provenance flag to pnpm publish for supply chain transparency
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix marketplace not showing unsupported tools - add min_api and max_api to Supabase query
- Add min_api and max_api columns to Supabase SELECT query in toolRegistryManager
- Compute isSupported field in fetchAvailableTools() using VersionManager
- Include minAPI, maxAPI, and isSupported fields when mapping to ToolDetail in marketplace
- Fix bug where tools with minAPI higher than current ToolBox version were showing as valid
Scenario fixed: Tool with minAPI=1.2.2 on ToolBox v1.2.0 now correctly shows as "Not Supported"
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Disable install buttons for unsupported tools in marketplace and modal
- Add disabled attribute to install button in standard marketplace view (was only in compact)
- Pass isSupported field to tool detail modal view and controller
- Disable install button in modal for unsupported tools with helpful tooltip
- Add compatibility double-check in modal install handler
- Prevent installation attempts for incompatible tools across all UI entry points
Fixes: Tool detail modal now prevents installation of unsupported tools
Fixes: Standard marketplace view install button now disabled for unsupported tools
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix installed tools not showing compatibility status or preventing launch
- Add minAPI and maxAPI fields to createToolFromInstalledManifest
- Compute isSupported field using VersionManager.isToolSupported()
- Installed tools now correctly display "Not Supported" badge in sidebar
- Launch prevention now works for installed tools that become incompatible
Fixes scenario: Tool with minAPI=1.0.20, maxAPI=1.0.20 on ToolBox v1.2.0 (MIN_SUPPORTED_API=1.2.0) now shows as "Not Supported" in installed tools section and cannot be launched
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix cached tools not recomputing compatibility after ToolBox version changes
- Always recompute isSupported field in getTool() when returning cached tool
- Always recompute isSupported field in getAllTools() for cached tools
- Ensures tools that become incompatible after ToolBox update are properly detected
- Launch prevention now works correctly even for tools loaded before version update
Root cause: Cached Tool objects retained old isSupported value computed at load time
Fix: Recompute isSupported on every retrieval using current ToolBox version
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive logging to VersionManager for debugging compatibility issues
- Add console.log statements at each decision point in isToolSupported()
- Log minAPI, maxAPI, toolboxVersion, MIN_SUPPORTED_API_VERSION
- Log comparison results for version checks
- Log final compatibility decision (COMPATIBLE/INCOMPATIBLE)
This will help identify why tools with minAPI=1.0.20 are still launching when MIN_SUPPORTED_API_VERSION=1.2.0 and toolbox version=1.2.0
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add stack trace logging to identify where legacy tool check is called from
- Add stack trace to all isToolSupported() calls
- Move logging before legacy check to capture ALL calls
- This will help identify which code path is calling isToolSupported without version parameters
Debug info will show exactly where in the code the second (legacy) call originates from
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix launch prevention by migrating version fields to installed tool manifests
ROOT CAUSE IDENTIFIED: Installed tool manifest.json files don't have minAPI/maxAPI fields.
When tools load for launch, they read from manifest without version info, causing
isToolSupported() to return COMPATIBLE as "legacy tool".
SOLUTION: Add manifest migration in loadTool():
- Check if installed manifest is missing version fields
- Fetch version info from Supabase registry
- Update local manifest.json with minAPI/maxAPI
- Tool will now correctly show as INCOMPATIBLE and prevent launch
NEW METHODS:
- toolRegistryManager.getToolFromRegistry() - fetch tool from Supabase
- toolRegistryManager.updateInstalledManifest() - update local manifest
CLEANUP:
- Removed all debug logging from VersionManager.isToolSupported()
This fix ensures all installed tools (even those installed before version checking
was implemented) will have their compatibility correctly determined.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix launch prevention by clearing tool cache on uninstall
ROOT CAUSE: Tools were remaining in memory cache after uninstall. When reinstalled
with updated manifest (including minAPI/maxAPI), the old cached tool object (without
version fields) was reused, causing isToolSupported() to be called with undefined
values and return COMPATIBLE.
FIX: Clear tool from cache when uninstalled. This ensures that on reinstall, the
tool is reloaded from the new manifest with correct version information.
REVERTED: Previous manifest migration commit (9713490) - was unnecessary and
incorrect approach.
CLEANUP: Removed all debug logging from VersionManager.isToolSupported()
This fix ensures tools properly show "Not Supported" badge and prevent launch when
incompatible, even after uninstall/reinstall cycles.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Added proper fix after copilot wasnt able to fix it :)
* Update src/renderer/modals/toolDetail/controller.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: clarify minAPI and maxAPI comments in Tool interface
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update permissions for publish-types jobs in release workflows
* fix: replace pnpm with npm for publishing @pptb/types
* fix: update job dependencies and version handling in release workflows
* fix: update versioning scheme from dev to beta for insider builds
* Relationshipdefinitions setname (#415)
* fix: add relationshipdefinition to entity metadata mapping in DataverseManager
* fix: remove commented-out debug code in DataverseManager
* Update src/main/managers/dataverseManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: add registry URL configuration for npm publishing
* fix: comment out publish-types jobs in release workflows
* feat: implement custom protocol handler for tool installation via pptb:// links (#419)
* feat: implement custom protocol handler for tool installation via pptb:// links
* Update src/main/managers/protocolHandlerManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/protocolHandlerManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: ensure pptb:// deep links are never dropped on cold launch or early macOS open-url (#420)
* Initial plan
* fix: move protocol handler early listeners before whenReady() and buffer deep links until renderer ready
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* feat: Show tool details as a tab instead of a modal dialog (#421)
* Initial plan
* feat: show tool details as a tab instead of a modal dialog
- Add HIDE_ALL IPC channel to hide all BrowserViews when showing detail tabs
- Add hideToolWindows() IPC handler in ToolWindowManager and expose via preload
- Add isDetailTab flag to OpenTool type for distinguishing detail tabs
- Add #tool-detail-content-panel div to index.html for inline content rendering
- Add openToolDetailTab() function in toolManagement.ts with full tab lifecycle
- Modify switchToTool() to handle detail tabs (hide BrowserViews, show panel)
- Modify closeTool() to handle detail tabs (no BrowserView to close)
- Modify saveSession() to exclude detail tabs from persistence
- Replace modal-based openToolDetail() in marketplaceManagement.ts with tab approach
- Add renderToolDetailContent() that renders tool details directly in the renderer
- Open all links (review, repo, website, README links) via toolboxAPI.openExternal
- Add CSS styles for tool-detail-content-panel in styles.scss
- Add visual indicator for active tool detail tabs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: improve type safety for marked library loader and add XSS comment
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: tool detail tab full-width, ' - Details' label, and README loading
- Hide tool-panel-content when detail tab is active so the detail panel
gets the full available space (not 50/50 split)
- Restore tool-panel-content when switching back to a real tool tab
- Tab now shows '{Tool Name} - Details' label as requested
- Fix README not loading: replace CDN-loaded marked with bundled dependency
(cdn.jsdelivr.net was blocked by CSP script-src)
- Add https://*.blob.core.windows.net to connect-src in CSP so README
files hosted on Azure Blob can be fetched
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address PR review security and correctness issues in tool detail tab
- XSS: configure marked renderer to escape both block and inline raw HTML
(html() handles Tokens.HTML + Tokens.Tag) preventing event handler injection
- Race condition: loadToolReadme() now checks data-tab-id on the detail
panel after async fetch and on error to discard stale results
- Fake toolId: detail tab entries use empty string toolId so connections
are never persisted under a synthetic tab ID
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix bug where Restart & Install Now does nothing (#427)
* Initial plan
* fix: Restart & Install Now sends install channel after download-in-modal transition
Root cause: CONFIG is JSON-serialized at modal creation with type:"available".
When a download completes while the "available" modal is still open, the UI
switches to show "Restart & Install Now" but CONFIG.type remains "available",
so clicking the button sent the `download` channel again (re-triggering a
download) instead of the `install` channel (calling quitAndInstall).
Fix:
- Introduce mutable `effectiveType` in controller.ts (init from CONFIG.type,
updated to "downloaded" on update:downloaded message). All click/dismiss
logic uses effectiveType instead of CONFIG.type.
- Add setErrorState() helper and handle update:error message so failures
surface in the modal rather than silently disabling the button.
- In autoUpdateManagement.ts, catch downloadUpdate/quitAndInstall failures
and forward them to the modal via sendBrowserWindowModalMessage.
- Forward onUpdateError events to the modal when it is open so
autoUpdater-level errors (e.g. missing installer path) are also shown.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address PR review comments on dismiss channel and error color state
- autoUpdateManagement.ts: add explicit dismiss branch in onMessage to make
clear the channel is intentionally received with no side-effect (autoInstallOnAppQuit
handles install-on-exit automatically)
- controller.ts: reset progressLabel.style.color to "" in setDownloadingState so
the hard-coded error red is cleared when the user retries after an error
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update launchTool and createTab functions to handle environment names in tool tabs (#424)
* fix: update launchTool and createTab functions to handle environment names in tool tabs
[Feature]: Add connection name to tool header
Fixes #370
* Initial plan
* fix: use getById, connection name+env, and normalize error in createTab
Co-authored-by: LinkeD365 <43988771+LinkeD365@users.noreply.github.com>
* fix: update createTab function to remove environment from connection labels
* Initial plan
* fix: make createTab sync with async connection subtext, parallel fetches, rename vars
Co-authored-by: LinkeD365 <43988771+LinkeD365@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Show browser profile badge in connection selection modals (#429)
* Initial plan
* Add browser profile badge to connection selection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: add browser icons and update connection selection modals
* Address PR review: use ?inline for icons, fix double badge call, escape HTML fields
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* fix: Improve CSP exception modal wording to be user-friendly (#428)
* Initial plan
* fix: improve CSP exception modal wording to be user-friendly
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: HTML-escape CSP modal content and rename allDomains to allSources
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: improve wording in CSP exception modal for clarity and trust
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Fix: Toast notifications no longer always-on-top; add configurable display duration (#432)
* Initial plan
* fix: remove alwaysOnTop from toast notifications and add notification duration setting
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address review comments - use DEFAULT_NOTIFICATION_DURATION constant and fix duration=0 handling
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: pass notification duration as-is so defaultNotificationDuration is respected
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add Category and Environment Color to Dataverse connections (#433)
* Initial plan
* Add Category and Environment Color to connections with two-column modal layout
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Increase add/edit connection modal width to 920px to match select multi-connection modal
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add categoryColor support and connection grouping by category
- Add categoryColor to DataverseConnection and UIConnectionData types
- Add categoryColor to ToolSafeConnection in toolPreloadBridge
- Add categoryColor to ConnectionFormPayload and buildConnectionFromPayload
- Pass category, environmentColor, categoryColor in populate handlers
- Group sidebar connections by category with collapsible headers
- Add category filter dropdown to sidebar with dynamic population
- Update updateToolPanelBorder to support inline environmentColor/categoryColor
- Apply environmentColor as inline border style on tool panel
- Apply categoryColor as inline border-bottom on active tool tab
- Restructure add/edit connection modals: two-col layout with browser
settings and auth fields side by side
- Add categoryColor color picker to add/edit connection modals
- Show environmentColor and categoryColor badges in select/multi-select modals
- Add connection-group CSS for grouped sidebar display
- Add category-badge and auth-fields-column CSS to sharedStyles
- Add category filter section to connections sidebar in index.html
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix HTML escaping in category group rendering and simplify group toggle
- Use escapeHtml() for category names in option values and group data attrs
- Use closest() to find sibling group-items instead of CSS.escape querySelector
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add categoryColor, env color to tool border, category grouping/filter in sidebar, restructured modal layout, color in select modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply environmentColor to footer status elements; fix multi-connection gradient border
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review: escape HTML, fix color sentinel, keyboard a11y for group headers
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: update default color values for environment and category in add/edit connection modals
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* feat(packages): add pptb-validate CLI for pre-publish tool validation (#436)
* Initial plan
* feat: add pptb-validate CLI for tool package validation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* docs: add long-term plan for shared @pptb/validation package
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: update tool validation script and README for improved usability
* feat(validate): warn on missing optional fields (icon, website, funding)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat(validate): improve funding validation logic in tool validation script
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat(validate): add 'media-src' to valid CSP directives in validation logic
* fix(validate): reject Windows absolute paths and backslashes in icon paths
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Allow toolmakers to explain why they need CSP exceptions with selective optional domain consent (#431)
* Initial plan
* Allow toolmakers to explain why they need CSP exceptions
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Split CSP modal into required/optional sections with selective opt-in checkboxes
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Store required domains in CSP consent record alongside optional domains
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Consolidate CSP consent storage and add disabled checkboxes for required domains
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update CSP documentation link in exception modal
* Update src/renderer/modals/cspException/view.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/renderer/modules/toolManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: enhance CSP exception domain display with additional styling
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: add alwaysOnTop option for auto update notification… (#437)
* fix: add alwaysOnTop option for modal windows and update notification text
* fix: ensure modal windows move to the top when opened
* fix: update action button text for update notification modal
* feat: Add category filter and grouping to connection selection modals (#440)
* Initial plan
* feat: add category filter and grouping to connection selection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove Sentry monitoring and replace with centralized console logging (#443)
* Initial plan
* feat: remove Sentry and replace with console logging
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Replace sentryHelper calls with direct console.* equivalents
- logInfo → console.info
- logWarn → console.warn
- logDebug → console.debug
- logCheckpoint → console.log
- captureException(err, ctx) → console.error(err) (ctx dropped)
- captureMessage(msg, level, ctx) → console.error/warn(msg) (ctx dropped)
- addBreadcrumb(...) → removed entirely
- wrapAsyncOperation(name, async () => { body }, ctx) → (async () => { body })()
- Removed all sentryHelper import lines across 26 files
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: resolve lint errors after sentryHelper removal
- Fix unterminated string literals in encryptionManager, terminalManager, toolRegistryManager
- Rename unused catch params to _error/_trigger to satisfy no-unused-vars rule
- Rename unused function param extra -> _extra in homepageManagement
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: replace console.* calls with centralized logger functions
Replace all direct console.info/warn/error/debug/log calls in src/main/
and src/renderer/modules/ with the corresponding logger functions from
the …
* Initial plan
* Fix macOS notarization failures with timestamps and signing improvements
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply macOS notarization fixes to nightly build workflow
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* chore: add macOS certificate files to .gitignore
* fix: update macOS code signing verification to skip spctl assessment
* fix: enhance macOS notarization steps to support multiple artifacts and improve error handling
* fix: update notarization scripts to support multiple asset types and improve error handling
* fix: update version to 1.1.3 in package.json
* feat: Associate browser profile with connections - visual tags and profile detection (#355)
* Initial plan
* Add browser profile support for interactive authentication
- Add browserType and browserProfile fields to DataverseConnection interface
- Implement browser-specific launch logic in AuthManager
- Update add/edit connection modals with browser selection UI
- Support Chrome, Edge, Firefox, and Brave browsers
- Fallback to default browser if profile not found
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback - use helper functions consistently
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Refactor: Extract browser logic into separate BrowserManager
- Create new BrowserManager class for browser detection and profile enumeration
- Remove browser-related code from AuthManager
- AuthManager now depends on BrowserManager via constructor injection
- Add IPC channels for browser detection and profile listing
- Update preload script to expose new browser APIs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Implement dynamic browser profile detection in UI
- Replace text input with dropdown for browser profiles
- Dynamically detect browser installation on selection
- Automatically load and populate browser profiles
- Show warning when selected browser is not installed
- Support both add and edit connection modals
- Add modal-warning CSS for user feedback
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix: Browser profile detection in modals
- Expose browser detection APIs in modalPreload.ts
- Fix browser type change event to properly trigger profile loading
- Set correct initial state for profile dropdown (No profile needed)
- Remove premature loadBrowserProfiles() call that ran before DOM ready
Fixes:
- Profile selector now loads data when browser is selected
- Browser detection APIs now available in modal context
- Initial dropdown state shows correct message
- Warning displays when browser not installed
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Enhance profile detection to show friendly names, support Chrome/Edge only
- Read actual profile names from Local State file (e.g., "Person 1", "Work")
- Fallback to reading individual Preferences files if Local State unavailable
- Remove Firefox and Brave browser support (Chrome and Edge only)
- UI now displays profile.name but stores profile.path for --profile-directory
- Update both add and edit connection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Move browser settings to separate section available for all auth types
- Move browser type and profile selectors out of interactive-only section
- Create new "Browser Settings (Optional)" section below Environment selector
- Apply browser settings to all authentication types (interactive, clientSecret, usernamePassword, connectionString)
- Browser profile used when tools need to open URLs with authentication
- Updated both add and edit connection modals
- Updated connectionManagement to apply browser settings to all auth types
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fixed style issue and added logos
* Add browser profile tag to connection cards in sidebar
- Add browserProfileName field to DataverseConnection type
- Display browser icon and profile name as tag on connection cards
- Tag shows Chrome/Edge icon with friendly profile name (e.g., "My Cool Profile")
- Tag positioned next to environment badge
- Update form controllers to capture and store profile name
- Add CSS styling for connection-browser-tag with browser icon
- Browser icons loaded from renderer/icons/logos/
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix modal hanging issue - improve browser profile name collection
- Fix collectFormData to safely handle empty profile selections
- Only capture browserProfileName when a profile is actually selected
- Add null-safe checks for selectedOptions array access
- Prevent attempting to read textContent from empty value options
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Revert "Fix modal hanging issue - improve browser profile name collection"
This reverts commit 607fde9bdc171cdaf3039153d6457ff8a3c4d814.
* Revert "Add browser profile tag to connection cards in sidebar"
This reverts commit e1cab02dfd7401b5555de63bee6e664eea96e4d8.
* feat: add browser profile name support in connection forms and UI
* Update src/renderer/modules/connectionManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/browserManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/browserManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/common/types/connection.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add optional file type filters to saveFile with extension-based auto-derivation (#354)
* Initial plan
* Add optional filters parameter to saveFile function
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix extension extraction to use path.extname for robust handling
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Signing executables for all platform (#377)
* fix: enable recursive file search for notarization in release workflows
* feat: add YAML regeneration steps for Windows, Linux, and macOS with correct SHA256 hashes
* feat: add repackaging step for portable ZIP with signed EXE in Windows workflows
* feat: Added support for Metadata CRUD operations (#356)
* fix: Enhance Label structure compliance and add polymorphic lookup support
This commit addresses documentation review findings and adds support for polymorphic lookup attributes (Customer/Regarding fields) to complete metadata CRUD operations implementation for issue #319.
## Type Definitions (src/common/types/dataverse.ts)
- Added `IsManaged?: boolean` property to LocalizedLabel interface
* Microsoft examples show IsManaged included in all attribute/relationship/optionset requests
* Properly tracks whether label originates from managed solution
- UserLocalizedLabel remains optional in Label interface
* Entity creation docs note it as read-only
* However, Microsoft's own examples for attributes, relationships, and optionsets include it in POST requests
* Implementation follows Microsoft's published examples
## DataverseManager Updates (src/main/managers/dataverseManager.ts)
- Updated buildLabel() helper method:
* Now creates LocalizedLabel with IsManaged: false property
* Includes UserLocalizedLabel property set to same LocalizedLabel instance
* Matches Microsoft's published examples for attribute/relationship creation
* Example output: { LocalizedLabels: [{ Label: "Text", LanguageCode: 1033, IsManaged: false }], UserLocalizedLabel: { Label: "Text", LanguageCode: 1033, IsManaged: false } }
- Added createPolymorphicLookupAttribute() method:
* Enables creation of lookup fields that reference multiple entity types (Customer, Regarding scenarios)
* Validates presence of non-empty Targets array with entity logical names
* Automatically sets AttributeType="Lookup" and AttributeTypeName={ Value: "LookupType" }
* Delegates to createAttribute() with proper polymorphic configuration
* Returns { AttributeId: string } matching API contract
* Comprehensive JSDoc with Customer (account/contact) and custom Regarding examples
- Enhanced createRelationship() JSDoc:
* Added CascadeConfiguration example with all cascade behaviors (Assign, Delete, Merge, Reparent, Share, Unshare)
* Shows proper RemoveLink delete behavior for lookup fields
- Enhanced updateRelationship() JSDoc:
* Added example demonstrating cascade configuration updates (RemoveLink → Cascade)
* Illustrates retrieve-modify-PUT pattern for relationship updates
- Added LocalizedLabel to imports from common types
## IPC Infrastructure (src/common/ipc/channels.ts, src/main/index.ts)
- Added CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel constant
* Value: "dataverse.createPolymorphicLookupAttribute"
- Registered IPC handler in main process:
* Supports both primary and secondary connection targets
* Extracts connectionId from WebContents based on connectionTarget parameter
* Wraps dataverseManager.createPolymorphicLookupAttribute() with error handling
* Proper cleanup with removeHandler() on application quit
## Preload Bridge (src/main/toolPreloadBridge.ts)
- Exposed createPolymorphicLookupAttribute in toolboxAPI.dataverse
- Exposed createPolymorphicLookupAttribute in window.dataverseAPI
- Both accept (entityLogicalName, attributeDefinition, options?, connectionTarget?) parameters
- Properly wrapped with ipcInvoke using CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel
## Public API Types (packages/dataverseAPI.d.ts)
- Added createPolymorphicLookupAttribute method signature to DataverseAPI interface
- Comprehensive JSDoc documentation:
* Customer lookup example (account/contact on new_order entity)
* Multi-entity Regarding example (account/contact/custom entities on new_note)
* Documents Targets array requirement
* Notes metadata publish requirement
* Shows buildLabel() usage in examples
- Method signature: (entityLogicalName, attributeDefinition, options?, connectionTarget?) => Promise<{ AttributeId: string }>
## Validation
- TypeScript compilation: ✅ No errors
- ESLint: ✅ 0 errors (TypeScript version warning acceptable)
- All 12 implementation tasks completed
- Documentation compliance verified against 5 Microsoft Learn articles
## Microsoft Documentation References
- Attribute creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-column-definitions-using-web-api
- Relationship creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-relationships-using-web-api
- Option sets: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-optionsets
- Polymorphic lookups: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/multitable-lookup
- Entity creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-definitions-using-web-api
Closes #319 metadata CRUD operations (enhancement for polymorphic lookups)
* fix: improve metadata CRUD error handling and add comprehensive documentation
FIXES (Code Review Issues):
1. **Metadata creation methods now throw descriptive errors on missing headers**
- createEntityDefinition, createAttribute, createRelationship, createGlobalOptionSet
- Previously returned empty strings silently when OData-EntityId header missing
- Now throw explicit errors: "Failed to retrieve MetadataId from response. The OData-EntityId header was missing."
- Guides users to identify real issues (network failures, API changes, etc.)
2. **GET_ATTRIBUTE_ODATA_TYPE IPC handler now enforces type safety**
- Added runtime enum validation against AttributeMetadataType values
- Removed unsafe `as any` cast that bypassed TypeScript's type system
- Throws descriptive error listing all valid types when invalid value provided
- Example: "Invalid attribute type: 'InvalidType'. Valid types are: String, Integer, Boolean, ..."
TECHNICAL DISCOVERY:
**Dataverse metadata operations return HTTP 204 No Content with NO response body**:
- Standard operations (entity, attribute, relationship, global option set): 204 No Content
- Only OData-EntityId header contains the created MetadataId
- Empty response body → makeHttpRequest returns `response.data = {}`
- Exception: CreateCustomerRelationships action returns 200 OK with JSON body containing AttributeId and RelationshipIds
This discovery led to abandoning a proposed "fallback to response body" approach, as responseData["MetadataId"] would always be undefined for metadata operations.
DOCUMENTATION IMPROVEMENTS:
1. **execute() method**: Added comprehensive JSDoc with examples for:
- CreateCustomerRelationships action (customer lookup creation with 200 OK response)
- InsertStatusValue action (status choice column values with StateCode)
- UpdateStateValue action (state value metadata updates)
- Bound vs unbound actions/functions
2. **queryData() method**: Added examples demonstrating:
- Retrieving global option sets by name: `GlobalOptionSetDefinitions(Name='name')`
- Retrieving all global option sets with filters
- Retrieving by MetadataId
3. **createPolymorphicLookupAttribute()**: Added note about CreateCustomerRelationships alternative
4. **insertOptionValue()**: Added note about InsertStatusValue for status choice columns
5. **createGlobalOptionSet()**: Added retrieval example using queryData()
BENEFITS:
- **Fail-Fast Approach**: Clear errors replace silent failures, improving debuggability
- **Type Safety**: Runtime enum validation prevents invalid API calls
- **Complete Coverage**: All metadata operations from Microsoft documentation are supported via existing methods (execute, queryData)
- **Developer Guidance**: JSDoc examples show how to use actions like CreateCustomerRelationships, InsertStatusValue, UpdateStateValue
- **No New Methods Needed**: Generic execute() and queryData() methods handle all special cases
VALIDATION:
- ✅ TypeScript compilation passed (pnpm run typecheck)
- ✅ Linting passed (pnpm run lint - 0 errors)
- ✅ Application builds successfully (pnpm build)
- ✅ All 6 file edits applied successfully
* feat(dataverse): add whitelist-based header validation for metadata operations
Implemented comprehensive security validation for custom headers in metadata
operations to prevent header injection attacks and API compliance issues.
SECURITY ENHANCEMENTS:
- Added validateMetadataHeaders() method with whitelist-based validation
- Validates all custom headers against allowed list from Microsoft documentation
- Blocks attempts to override protected headers (Authorization, Content-Type, etc.)
- Case-insensitive header matching per HTTP specification (RFC 2616)
- Detailed error messages showing invalid headers and allowed alternatives
ALLOWED CUSTOM HEADERS (per Microsoft Dataverse Web API docs):
- MSCRM.SolutionUniqueName: Associates metadata changes with solutions
- MSCRM.MergeLabels: Controls label merging behavior (true/false)
- Consistency: Forces reading latest version (value: "Strong")
- If-Match: Standard HTTP header for optimistic concurrency control
- If-None-Match: Standard HTTP header for caching control
PROTECTED HEADERS (never allowed in customHeaders):
- Authorization, Accept, Content-Type, OData-MaxVersion, OData-Version,
Prefer, Content-Length (all controlled by makeHttpRequest)
IMPLEMENTATION:
- Created ALLOWED_METADATA_HEADERS constant with whitelist (5 headers)
- Created PROTECTED_HEADERS constant with blacklist (7 headers)
- Integrated validation into buildMetadataHeaders() for automatic coverage
- All metadata operations now automatically validated:
* createEntityDefinition / updateEntityDefinition
* createAttribute / updateAttribute
* createRelationship / updateRelationship
* createGlobalOptionSet / updateGlobalOptionSet
* createPolymorphicLookup
BENEFITS:
- Prevents header injection attacks and accidental header overrides
- Ensures API compliance with Microsoft's documented patterns
- Provides clear developer feedback when invalid headers are used
- Defense-in-depth validation even for type-safe inputs
DOCUMENTATION REFERENCES:
Based on thorough review of 6 Microsoft Learn articles covering all metadata
operation types (entity, attribute, relationship, option set operations).
Changes maintain backward compatibility - all existing code uses valid headers
through typed MetadataOperationOptions interface.
* fix(types): replace 'any' with MetadataOperationOptions in IPC handlers
Improved type safety in metadata operation IPC handlers by replacing all
occurrences of 'options?: any' with proper 'options?: MetadataOperationOptions'
type annotation.
CHANGES:
- Added MetadataOperationOptions to type imports from ../common/types
- Updated 9 IPC handler signatures to use MetadataOperationOptions:
* CREATE_ENTITY_DEFINITION
* UPDATE_ENTITY_DEFINITION
* CREATE_ATTRIBUTE
* UPDATE_ATTRIBUTE
* CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE
* CREATE_RELATIONSHIP
* UPDATE_RELATIONSHIP
* CREATE_GLOBAL_OPTION_SET
* UPDATE_GLOBAL_OPTION_SET
BENEFITS:
- Eliminates use of 'any' type, maintaining TypeScript strict mode compliance
- Provides IntelliSense and autocomplete for options parameter
- Type safety ensures only valid options (solutionUniqueName, mergeLabels,
consistencyStrong) can be passed through IPC layer
- Consistency with DataverseManager method signatures
- Compile-time validation of option properties
This change maintains backward compatibility while adding proper type checking
for all metadata operation options passed from tools via IPC.
* chore: update version to 1.0.19 in package.json
* feat(preload): sync metadata CRUD operations with toolPreloadBridge
Synchronized preload.ts with toolPreloadBridge.ts to ensure both the main
ToolBox UI and tool windows have identical metadata operation APIs available.
This maintains API parity and enables future metadata manipulation from the
main UI if needed.
ADDED METADATA OPERATIONS (22 new methods in dataverse namespace):
Metadata Helper Utilities:
- buildLabel: Build localized Label objects for metadata operations
- getAttributeODataType: Get OData type string for attribute type enums
Entity (Table) Metadata CRUD:
- createEntityDefinition: Create new entity/table definitions
- updateEntityDefinition: Update existing entity definitions (PUT)
- deleteEntityDefinition: Delete entity definitions
Attribute (Column) Metadata CRUD:
- createAttribute: Create new attributes/columns on entities
- updateAttribute: Update existing attribute definitions (PUT)
- deleteAttribute: Delete attributes from entities
- createPolymorphicLookupAttribute: Create multi-table lookup attributes
Relationship Metadata CRUD:
- createRelationship: Create 1:N, N:N, or polymorphic relationships
- updateRelationship: Update existing relationship definitions (PUT)
- deleteRelationship: Delete relationships
Global Option Set (Choice) Metadata CRUD:
- createGlobalOptionSet: Create new global option sets/choices
- updateGlobalOptionSet: Update existing global option sets (PUT)
- deleteGlobalOptionSet: Delete global option sets
Option Value Modification Actions (OData Actions):
- insertOptionValue: Insert new option values into option sets
- updateOptionValue: Update existing option values (labels, etc.)
- deleteOptionValue: Delete option values from option sets
- orderOption: Reorder option values within option sets
BENEFITS:
- API parity between main UI (preload.ts) and tool windows (toolPreloadBridge.ts)
- Main ToolBox UI can now perform metadata operations if needed in future
- Consistent API surface across all preload contexts
- Future-proofing for internal metadata management UI features
- All operations support primary/secondary connection targeting
IMPLEMENTATION NOTES:
- All methods maintain same signatures as toolPreloadBridge.ts
- Options parameter uses Record<string, unknown> for flexibility
- Connection targeting via optional connectionTarget parameter
- Validated header whitelisting enforced by DataverseManager layer
This synchronization ensures both contexts stay in sync as the metadata API
evolves and provides maximum flexibility for future UI enhancements.
---------
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Fix loading overlay positioning and add manual dismiss button (#379)
* Initial plan
* Fix loading screen to only block tool panel, not entire window
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review: Fix listener leak and simplify null coalescing
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix IPC listener cleanup: use ipcMain.on instead of once
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix loading overlay bounds calculation and add close button
- Get bounds directly from active tool BrowserView instead of renderer
- Add getActiveToolBounds() method to ToolWindowManager
- Remove rounded corners from overlay container
- Add close button to manually dismiss loading overlay
- Make overlay window focusable and closable
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Improve close button accessibility and contrast
- Add aria-label for screen reader support
- Increase background opacity for better contrast (0.1 -> 0.15)
- Add visible focus indicator with blue border and shadow
- Improve border visibility (0.2 -> 0.3 opacity)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix overlay positioning and explicitly remove all rounded corners
- Use content bounds (screen coordinates) instead of incorrectly adding window bounds to BrowserView bounds
- Explicitly set border-radius:0 on overlay-container and close-button
- BrowserView bounds are content-relative, overlay BrowserWindow needs screen coordinates
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback: fix shutdown handling, HTML escaping, and error telemetry
- Add isMainWindowClosing flag to allow overlay to close during app shutdown
- Escape HTML in loading message to prevent injection attacks
- Improve error handling with captureException and full context (activeToolId, tags)
- Properly destroy overlay window in cleanup
- Add close listener on main window to set shutdown flag
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Refine code review fixes: use specific listener reference and clarify HTML escaping
- Store closeHandler reference to remove specific listener (not all listeners)
- Add comment explaining critical order of HTML entity replacements
- Prevent potential issues with removeAllListeners affecting other code
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Polish destroy logic for better clarity and consistency
- Move overlayWindow null assignment inside if block for logical consistency
- Set closeHandler to null after cleanup for better flow
- Clearer separation of window cleanup vs handler cleanup
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update release date formatting in workflows for consistency (#383)
* fix: clean up toolboxAPI type definitions and improve connection handling (#387)
* feat: add getCSDLDocument API for retrieving OData endpoint (#384) (#385)
* feat: add getCSDLDocument API for retrieving OData endpoint (#384)
Add new getCSDLDocument() method to DataverseAPI that retrieves the complete
CSDL/EDMX metadata document from Dataverse's OData $metadata endpoint.
Key Features:
- Returns raw XML containing complete schema metadata (entities, attributes,
relationships, actions, functions, complex types, enum types)
- Supports gzip/deflate compression for optimal transfer (70-80% size reduction)
- Automatic decompression handling using Node.js zlib module
- Multi-connection support (primary/secondary) for advanced tools
- Response size: 1-5MB typical, up to 10MB+ for complex environments
Implementation:
- Added GET_CSDL_DOCUMENT IPC channel to channels.ts
- Implemented getCSDLDocument() in DataverseManager with:
- Custom HTTPS request handler (avoids JSON parsing)
- Accept-Encoding: gzip, deflate headers
- Automatic decompression via zlib.gunzip/inflate
- Buffer-based response handling for binary data
- Registered IPC handler in index.ts with connection targeting support
- Exposed method in toolPreloadBridge.ts and preload.ts
- Added comprehensive TypeScript definitions in dataverseAPI.d.ts
Use Cases:
- Build Dataverse REST Builder (DRB) clone tools
- Create intelligent query builders and code generators
- Generate TypeScript interfaces from schema
- Explore entity relationships and metadata
- Validate action/function parameters
Naming Rationale:
Method named getCSDLDocument() (not getMetadata()) to avoid confusion with
existing entity metadata operations like getEntityMetadata() and
getAllEntitiesMetadata(). CSDL (Common Schema Definition Language) clearly
indicates it returns the OData service document.
Related: #384
* fix: expose getCSDLDocument on window.dataverseAPI for direct tool access
Fixed issue where getCSDLDocument was only accessible via
window.toolboxAPI.dataverse.getCSDLDocument but not directly on
window.dataverseAPI.getCSDLDocument like other Dataverse operations.
Changes:
- Added getCSDLDocument to toolPreloadBridge.ts dataverseAPI namespace
- Now consistent with other operations (getSolutions, queryData, etc.)
- Tools can call dataverseAPI.getCSDLDocument() directly as expected
This ensures getCSDLDocument follows the same exposure pattern as all
other Dataverse API methods.
* fix: decompress error responses in getCSDLDocument for readable error messages
Previously, error responses (non-200 status codes) were converted directly
from Buffer to UTF-8 string without checking for compression. Since the
request includes 'Accept-Encoding: gzip, deflate' header, Dataverse may
return compressed error responses, resulting in garbled error messages.
Changes:
- Added decompression logic to error response path
- Check content-encoding header (gzip/deflate/none)
- Decompress error body before converting to string
- Added try-catch to handle decompression failures gracefully
- Error messages now readable regardless of compression
This mirrors the success path's decompression logic and ensures consistent
handling of both success and error responses.
* File System cleanup (#389)
* fix: clean up toolboxAPI type definitions and improve connection handling
* fix: implement filesystem access management for tools with user consent model
* Fix filesystem access tracking to use instanceId instead of toolId (#390)
* Initial plan
* fix: track filesystem access per instance instead of per tool
This change fixes the issue where closing one instance of a tool would
revoke filesystem access for all other instances of the same tool.
Changes:
- Updated ToolFileSystemAccessManager to use instanceId as key instead of toolId
- Added getInstanceIdByWebContents() method to ToolWindowManager
- Updated all filesystem IPC handlers to use instanceId
- Updated closeTool() to revoke access only for the specific instance
This ensures that each tool instance maintains its own filesystem
permissions independently, allowing multiple instances of the same tool
to run simultaneously without interfering with each other.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* refactor: eliminate code duplication in toolWindowManager methods
Refactor getToolIdByWebContents() to call getInstanceIdByWebContents()
and extract the toolId from the result, eliminating duplicated loop logic.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* fix: update force check-in timestamp in README.md
* fix: calculate and log SHA256 and SHA512 hashes in release workflows
* chore: update RELEASE_NOTES.md for version 1.1.3 with highlights and fixes
* fix: update version to 1.0.20 in package.json
* Fix Windows and macOS auto-update downloading wrong architecture installer (#397)
* Initial plan
* Add Windows multi-architecture support to latest.yml generation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply Windows YAML merge fix to nightly-release workflow
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add standalone script to generate merged Windows latest.yml
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add buildScripts/latest.yml to gitignore and remove example file
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add macOS multi-architecture support to latest-mac.yml generation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove legacy build scripts and add new merge scripts for Windows and macOS
- Deleted old merge scripts: merge-macos-latest-yml.sh, merge-windows-latest-yml.sh, test-macos-build.sh, verify-build.sh
- Added new merge scripts for Windows and macOS with improved functionality and documentation.
- Created README for merge scripts detailing usage and troubleshooting.
- Implemented new test and verification scripts for macOS builds to ensure proper packaging and structure.
* fix: correct path to verify-build.sh script in build workflow
* Update buildScripts/sh/merge-latest-yml.sh
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update .github/workflows/prod-release.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update .github/workflows/nightly-release.yml
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update macOS release scripts to use ZIP artifacts instead of DMG files
* fix: add webresource to entity mapping in DataverseManager (#402)
* Move marketplace to azure blob (#403)
* Add support for bundled SVG icons in tools with backward compatibility (#380)
* Initial plan
* Add SVG icon support with pptb-webview protocol for bundled icons
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review feedback: fix recent tools icon handling and add HTML escaping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive HTML escaping for XSS prevention in icon URLs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Improve accessibility and eliminate code duplication in HTML escaping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add defensive URL validation to prevent JavaScript protocol injection
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix CodeQL warning by blocking vbscript protocol in URL validation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove HTTP(S) icon support, change path to dist/ relative, rename iconUrl to icon
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update ToolManifest comment to reflect bundled icons only (no HTTP URLs)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add support for new Supabase 'icon' column with backward compatibility fallback to 'iconurl'
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix CSP error by allowing HTTP(S) URLs for marketplace icon display
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add pptb-webview protocol to CSP img-src to allow local SVG icon loading
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: add SVG icon support and improve icon URL resolution
* feat: implement theme-aware SVG icon support with CSS masks and improve icon rendering
* refactor: remove tool icon configuration section from README.md
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Move tool distribution from GitHub Releases to Azure Blob Storage (#400)
* Initial plan
* Add Azure Blob Storage support for tool distribution and registry fallback
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove hard-coded Azure Blob storage account name; resolve URLs at runtime from AZURE_BLOB_BASE_URL
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Simplify registry.json downloadUrl to filename-only; packages/ prefix added automatically at runtime
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Use per-tool version folder layout in Azure Blob, mirroring GitHub Releases structure
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Read download URL from new 'download' column in Supabase tools table, fall back to 'downloadurl'
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update Azure Blob Storage migration documentation to reflect new package structure
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* feat: enhance ToolManager to create tools from installed manifests and improve tool retrieval logic
* Update src/main/constants.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Azure Blob test download URL to dedicated test path (#404)
* Initial plan
* Update test tool download URL to /test/pptb-standard-sample-tool-download-test.tar.gz
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix resolveDownloadUrl to include packages/ prefix for Azure Blob Storage paths (#405)
* Initial plan
* fix: include packages/ prefix in resolveDownloadUrl for Azure Blob Storage
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix: include `icon` field in `fetchAzureBlobRegistry` tool mapping (#406)
* Initial plan
* fix: include icon field in fetchAzureBlobRegistry mapping
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/main/index.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update version to 1.2.0 in package.json
* Replace native OS update dialogs with themed custom modal (#408)
* Initial plan
* Add modern themed update notification modal dialog
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address review comments: reword restart warning and extract highlights from release notes
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/renderer/modules/autoUpdateManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add global search command palette to activity bar (#409)
* Initial plan
* Add global search command palette to activity bar
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Enhance global search: launch tools, show marketplace detail, focus settings
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Update src/renderer/index.html
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Improve tool load time (#410)
* Improve tool load time
* Update src/renderer/index.html
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add tool version compatibility checking with proper cache management (#378)
* Initial plan
* Add version compatibility types and backend logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add UI components for tool version compatibility
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add GitHub workflow steps for version sync and @pptb/types publishing
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive documentation for tool version compatibility feature
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add implementation checklist for version compatibility feature
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix code review issues: improve version comparison and validation logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix documentation to match corrected implementation logic
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix compatibility logic to support forward compatibility as requested
- Remove maxAPI restriction - tools built with older APIs work on newer ToolBox
- Add MIN_SUPPORTED_API_VERSION check to prevent tools using deprecated APIs
- Update documentation with correct examples matching user's requirements
- Tool with minAPI="1.0.0", maxAPI="1.0.4" now works on ToolBox v1.0.5
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* docs: enhance TOOL_VERSION_COMPATIBILITY.md with clearer formatting and examples for version checks
* Refactor version logic into VersionManager and correct data flow
- Create new VersionManager class to handle all version comparison and compatibility checking
- Move compareVersions and isToolSupported functions from toolsManager to VersionManager
- Update toolRegistryManager to only read version info from Supabase (not from package.json/npm-shrinkwrap)
- Version data (min_api, max_api) is now pre-processed during tool intake and stored in database
- Update documentation to reflect corrected data flow
- toolsManager now uses VersionManager.isToolSupported() for compatibility checks
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Use app.getVersion() instead of TOOLBOX_VERSION constant and create reusable npm publish workflow
- Replace TOOLBOX_VERSION constant with app.getVersion() call in VersionManager
- Remove TOOLBOX_VERSION from constants.ts and vite.config.ts
- Create standalone publish-npm-types.yml workflow with trusted publishing support
- Update prod-release.yml to use reusable workflow for npm publishing
- Update nightly-release.yml to use reusable workflow for npm beta publishing
- Add id-token: write permission for npm trusted publishing
- Add --provenance flag to pnpm publish for supply chain transparency
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix marketplace not showing unsupported tools - add min_api and max_api to Supabase query
- Add min_api and max_api columns to Supabase SELECT query in toolRegistryManager
- Compute isSupported field in fetchAvailableTools() using VersionManager
- Include minAPI, maxAPI, and isSupported fields when mapping to ToolDetail in marketplace
- Fix bug where tools with minAPI higher than current ToolBox version were showing as valid
Scenario fixed: Tool with minAPI=1.2.2 on ToolBox v1.2.0 now correctly shows as "Not Supported"
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Disable install buttons for unsupported tools in marketplace and modal
- Add disabled attribute to install button in standard marketplace view (was only in compact)
- Pass isSupported field to tool detail modal view and controller
- Disable install button in modal for unsupported tools with helpful tooltip
- Add compatibility double-check in modal install handler
- Prevent installation attempts for incompatible tools across all UI entry points
Fixes: Tool detail modal now prevents installation of unsupported tools
Fixes: Standard marketplace view install button now disabled for unsupported tools
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix installed tools not showing compatibility status or preventing launch
- Add minAPI and maxAPI fields to createToolFromInstalledManifest
- Compute isSupported field using VersionManager.isToolSupported()
- Installed tools now correctly display "Not Supported" badge in sidebar
- Launch prevention now works for installed tools that become incompatible
Fixes scenario: Tool with minAPI=1.0.20, maxAPI=1.0.20 on ToolBox v1.2.0 (MIN_SUPPORTED_API=1.2.0) now shows as "Not Supported" in installed tools section and cannot be launched
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix cached tools not recomputing compatibility after ToolBox version changes
- Always recompute isSupported field in getTool() when returning cached tool
- Always recompute isSupported field in getAllTools() for cached tools
- Ensures tools that become incompatible after ToolBox update are properly detected
- Launch prevention now works correctly even for tools loaded before version update
Root cause: Cached Tool objects retained old isSupported value computed at load time
Fix: Recompute isSupported on every retrieval using current ToolBox version
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add comprehensive logging to VersionManager for debugging compatibility issues
- Add console.log statements at each decision point in isToolSupported()
- Log minAPI, maxAPI, toolboxVersion, MIN_SUPPORTED_API_VERSION
- Log comparison results for version checks
- Log final compatibility decision (COMPATIBLE/INCOMPATIBLE)
This will help identify why tools with minAPI=1.0.20 are still launching when MIN_SUPPORTED_API_VERSION=1.2.0 and toolbox version=1.2.0
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add stack trace logging to identify where legacy tool check is called from
- Add stack trace to all isToolSupported() calls
- Move logging before legacy check to capture ALL calls
- This will help identify which code path is calling isToolSupported without version parameters
Debug info will show exactly where in the code the second (legacy) call originates from
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix launch prevention by migrating version fields to installed tool manifests
ROOT CAUSE IDENTIFIED: Installed tool manifest.json files don't have minAPI/maxAPI fields.
When tools load for launch, they read from manifest without version info, causing
isToolSupported() to return COMPATIBLE as "legacy tool".
SOLUTION: Add manifest migration in loadTool():
- Check if installed manifest is missing version fields
- Fetch version info from Supabase registry
- Update local manifest.json with minAPI/maxAPI
- Tool will now correctly show as INCOMPATIBLE and prevent launch
NEW METHODS:
- toolRegistryManager.getToolFromRegistry() - fetch tool from Supabase
- toolRegistryManager.updateInstalledManifest() - update local manifest
CLEANUP:
- Removed all debug logging from VersionManager.isToolSupported()
This fix ensures all installed tools (even those installed before version checking
was implemented) will have their compatibility correctly determined.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix launch prevention by clearing tool cache on uninstall
ROOT CAUSE: Tools were remaining in memory cache after uninstall. When reinstalled
with updated manifest (including minAPI/maxAPI), the old cached tool object (without
version fields) was reused, causing isToolSupported() to be called with undefined
values and return COMPATIBLE.
FIX: Clear tool from cache when uninstalled. This ensures that on reinstall, the
tool is reloaded from the new manifest with correct version information.
REVERTED: Previous manifest migration commit (9713490) - was unnecessary and
incorrect approach.
CLEANUP: Removed all debug logging from VersionManager.isToolSupported()
This fix ensures tools properly show "Not Supported" badge and prevent launch when
incompatible, even after uninstall/reinstall cycles.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Added proper fix after copilot wasnt able to fix it :)
* Update src/renderer/modals/toolDetail/controller.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: clarify minAPI and maxAPI comments in Tool interface
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: update permissions for publish-types jobs in release workflows
* fix: replace pnpm with npm for publishing @pptb/types
* fix: update job dependencies and version handling in release workflows
* fix: update versioning scheme from dev to beta for insider builds
* Relationshipdefinitions setname (#415)
* fix: add relationshipdefinition to entity metadata mapping in DataverseManager
* fix: remove commented-out debug code in DataverseManager
* Update src/main/managers/dataverseManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: add registry URL configuration for npm publishing
* fix: comment out publish-types jobs in release workflows
* feat: implement custom protocol handler for tool installation via pptb:// links (#419)
* feat: implement custom protocol handler for tool installation via pptb:// links
* Update src/main/managers/protocolHandlerManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/main/managers/protocolHandlerManager.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: ensure pptb:// deep links are never dropped on cold launch or early macOS open-url (#420)
* Initial plan
* fix: move protocol handler early listeners before whenReady() and buffer deep links until renderer ready
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
* feat: Show tool details as a tab instead of a modal dialog (#421)
* Initial plan
* feat: show tool details as a tab instead of a modal dialog
- Add HIDE_ALL IPC channel to hide all BrowserViews when showing detail tabs
- Add hideToolWindows() IPC handler in ToolWindowManager and expose via preload
- Add isDetailTab flag to OpenTool type for distinguishing detail tabs
- Add #tool-detail-content-panel div to index.html for inline content rendering
- Add openToolDetailTab() function in toolManagement.ts with full tab lifecycle
- Modify switchToTool() to handle detail tabs (hide BrowserViews, show panel)
- Modify closeTool() to handle detail tabs (no BrowserView to close)
- Modify saveSession() to exclude detail tabs from persistence
- Replace modal-based openToolDetail() in marketplaceManagement.ts with tab approach
- Add renderToolDetailContent() that renders tool details directly in the renderer
- Open all links (review, repo, website, README links) via toolboxAPI.openExternal
- Add CSS styles for tool-detail-content-panel in styles.scss
- Add visual indicator for active tool detail tabs
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: improve type safety for marked library loader and add XSS comment
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: tool detail tab full-width, ' - Details' label, and README loading
- Hide tool-panel-content when detail tab is active so the detail panel
gets the full available space (not 50/50 split)
- Restore tool-panel-content when switching back to a real tool tab
- Tab now shows '{Tool Name} - Details' label as requested
- Fix README not loading: replace CDN-loaded marked with bundled dependency
(cdn.jsdelivr.net was blocked by CSP script-src)
- Add https://*.blob.core.windows.net to connect-src in CSP so README
files hosted on Azure Blob can be fetched
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address PR review security and correctness issues in tool detail tab
- XSS: configure marked renderer to escape both block and inline raw HTML
(html() handles Tokens.HTML + Tokens.Tag) preventing event handler injection
- Race condition: loadToolReadme() now checks data-tab-id on the detail
panel after async fetch and on error to discard stale results
- Fake toolId: detail tab entries use empty string toolId so connections
are never persisted under a synthetic tab ID
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Fix bug where Restart & Install Now does nothing (#427)
* Initial plan
* fix: Restart & Install Now sends install channel after download-in-modal transition
Root cause: CONFIG is JSON-serialized at modal creation with type:"available".
When a download completes while the "available" modal is still open, the UI
switches to show "Restart & Install Now" but CONFIG.type remains "available",
so clicking the button sent the `download` channel again (re-triggering a
download) instead of the `install` channel (calling quitAndInstall).
Fix:
- Introduce mutable `effectiveType` in controller.ts (init from CONFIG.type,
updated to "downloaded" on update:downloaded message). All click/dismiss
logic uses effectiveType instead of CONFIG.type.
- Add setErrorState() helper and handle update:error message so failures
surface in the modal rather than silently disabling the button.
- In autoUpdateManagement.ts, catch downloadUpdate/quitAndInstall failures
and forward them to the modal via sendBrowserWindowModalMessage.
- Forward onUpdateError events to the modal when it is open so
autoUpdater-level errors (e.g. missing installer path) are also shown.
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address PR review comments on dismiss channel and error color state
- autoUpdateManagement.ts: add explicit dismiss branch in onMessage to make
clear the channel is intentionally received with no side-effect (autoInstallOnAppQuit
handles install-on-exit automatically)
- controller.ts: reset progressLabel.style.color to "" in setDownloadingState so
the hard-coded error red is cleared when the user retries after an error
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update launchTool and createTab functions to handle environment names in tool tabs (#424)
* fix: update launchTool and createTab functions to handle environment names in tool tabs
[Feature]: Add connection name to tool header
Fixes #370
* Initial plan
* fix: use getById, connection name+env, and normalize error in createTab
Co-authored-by: LinkeD365 <43988771+LinkeD365@users.noreply.github.com>
* fix: update createTab function to remove environment from connection labels
* Initial plan
* fix: make createTab sync with async connection subtext, parallel fetches, rename vars
Co-authored-by: LinkeD365 <43988771+LinkeD365@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* Show browser profile badge in connection selection modals (#429)
* Initial plan
* Add browser profile badge to connection selection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: add browser icons and update connection selection modals
* Address PR review: use ?inline for icons, fix double badge call, escape HTML fields
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* fix: Improve CSP exception modal wording to be user-friendly (#428)
* Initial plan
* fix: improve CSP exception modal wording to be user-friendly
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: HTML-escape CSP modal content and rename allDomains to allSources
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: improve wording in CSP exception modal for clarity and trust
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Fix: Toast notifications no longer always-on-top; add configurable display duration (#432)
* Initial plan
* fix: remove alwaysOnTop from toast notifications and add notification duration setting
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: address review comments - use DEFAULT_NOTIFICATION_DURATION constant and fix duration=0 handling
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: pass notification duration as-is so defaultNotificationDuration is respected
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add Category and Environment Color to Dataverse connections (#433)
* Initial plan
* Add Category and Environment Color to connections with two-column modal layout
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Increase add/edit connection modal width to 920px to match select multi-connection modal
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Add categoryColor support and connection grouping by category
- Add categoryColor to DataverseConnection and UIConnectionData types
- Add categoryColor to ToolSafeConnection in toolPreloadBridge
- Add categoryColor to ConnectionFormPayload and buildConnectionFromPayload
- Pass category, environmentColor, categoryColor in populate handlers
- Group sidebar connections by category with collapsible headers
- Add category filter dropdown to sidebar with dynamic population
- Update updateToolPanelBorder to support inline environmentColor/categoryColor
- Apply environmentColor as inline border style on tool panel
- Apply categoryColor as inline border-bottom on active tool tab
- Restructure add/edit connection modals: two-col layout with browser
settings and auth fields side by side
- Add categoryColor color picker to add/edit connection modals
- Show environmentColor and categoryColor badges in select/multi-select modals
- Add connection-group CSS for grouped sidebar display
- Add category-badge and auth-fields-column CSS to sharedStyles
- Add category filter section to connections sidebar in index.html
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix HTML escaping in category group rendering and simplify group toggle
- Use escapeHtml() for category names in option values and group data attrs
- Use closest() to find sibling group-items instead of CSS.escape querySelector
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add categoryColor, env color to tool border, category grouping/filter in sidebar, restructured modal layout, color in select modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Apply environmentColor to footer status elements; fix multi-connection gradient border
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Address code review: escape HTML, fix color sentinel, keyboard a11y for group headers
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: update default color values for environment and category in add/edit connection modals
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* feat(packages): add pptb-validate CLI for pre-publish tool validation (#436)
* Initial plan
* feat: add pptb-validate CLI for tool package validation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* docs: add long-term plan for shared @pptb/validation package
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat: update tool validation script and README for improved usability
* feat(validate): warn on missing optional fields (icon, website, funding)
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* feat(validate): improve funding validation logic in tool validation script
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update packages/lib/validate.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat(validate): add 'media-src' to valid CSP directives in validation logic
* fix(validate): reject Windows absolute paths and backslashes in icon paths
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Allow toolmakers to explain why they need CSP exceptions with selective optional domain consent (#431)
* Initial plan
* Allow toolmakers to explain why they need CSP exceptions
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Split CSP modal into required/optional sections with selective opt-in checkboxes
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Store required domains in CSP consent record alongside optional domains
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Consolidate CSP consent storage and add disabled checkboxes for required domains
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* fix: update CSP documentation link in exception modal
* Update src/renderer/modals/cspException/view.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/renderer/modules/toolManagement.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: enhance CSP exception domain display with additional styling
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: add alwaysOnTop option for auto update notification… (#437)
* fix: add alwaysOnTop option for modal windows and update notification text
* fix: ensure modal windows move to the top when opened
* fix: update action button text for update notification modal
* feat: Add category filter and grouping to connection selection modals (#440)
* Initial plan
* feat: add category filter and grouping to connection selection modals
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Remove Sentry monitoring and replace with centralized console logging (#443)
* Initial plan
* feat: remove Sentry and replace with console logging
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
* Replace sentryHelper calls with direct console.* equivalents
- logInfo → console.info
- logWarn → console.warn
- logDebug → console.debug
- logCheckpoint → console.log
- captureException(err, ctx) → console.error(err) (ctx dropped)
- captureMessage(msg, level, ctx) → console.error/warn(msg) (ctx dropped)
- addBreadcrumb(...) → removed entirely
- wrapAsyncOperation(name, async () => { body }, ctx) → (async () => { body })()
- Removed all sentryHelper import lines across 26 files
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: resolve lint errors after sentryHelper removal
- Fix unterminated string literals in encryptionManager, terminalManager, toolRegistryManager
- Rename unused catch params to _error/_trigger to satisfy no-unused-vars rule
- Rename unused function param extra -> _extra in homepageManagement
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: replace console.* calls with centralized logger functions
Replace all direct console.info/warn/error/debug/log calls in src/main/
and src/renderer/modules/ with the corresponding logger functions from
the …
Please fill in this template.