From bbde13ed5dde6e461926fd2372413c9bab6bcd10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20K=C5=82ys?= Date: Sat, 3 Oct 2026 21:13:41 +0200 Subject: [PATCH 1/4] Fix report rendering, filtering and export data preservation --- CHANGELOG.MD | 15 +- Private/ChartsAll/New-ApexChart.ps1 | 18 +- Private/ConvertFrom-HTMLTextLink.ps1 | 13 + Private/ConvertTo-HTMLScriptJson.ps1 | 22 ++ Private/New-InternalDiagram.ps1 | 6 +- Private/New-TableServerSide.ps1 | 9 +- Private/Protect-HTMLScriptData.ps1 | 11 + Private/Resolve-HTMLMarkdownImages.ps1 | 40 +++ Private/Tables/Add-TableContent.ps1 | 108 +------ Private/Tables/Add-TableFiltering.ps1 | 182 ++++-------- Private/Tables/Add-TableRowGrouping.ps1 | 54 +--- Private/Tables/Add-TableState.ps1 | 85 ------ Private/Tables/Convert-TableRowGrouping.ps1 | 82 ++--- Private/Tables/Get-TableExportScript.ps1 | 27 ++ Private/Tables/Get-TableInlineStyles.ps1 | 62 ++++ .../New-TableConditionalFormattingInline.ps1 | 6 +- Private/Tables/Set-TableButtons.ps1 | 144 +++++++++ Public/New-HTMLCalendar.ps1 | 2 +- Public/New-HTMLCarousel.ps1 | 2 +- Public/New-HTMLDiagram.ps1 | 6 +- Public/New-HTMLGage.ps1 | 4 +- Public/New-HTMLMap.ps1 | 2 +- Public/New-HTMLMarkdown.ps1 | 29 +- Public/New-HTMLOrgChart.ps1 | 2 +- Public/New-HTMLQRCode.ps1 | 4 +- Public/New-HTMLTab.ps1 | 7 +- Public/New-HTMLTabPanel.ps1 | 2 +- Public/New-HTMLTable.ps1 | 281 ++++-------------- Public/New-HTMLTableStyle.ps1 | 5 +- Public/New-HTMLText.ps1 | 44 +-- Public/New-HTMLTree.ps1 | 2 +- Public/New-HTMLWinBox.ps1 | 2 +- Public/New-NavTopMenu.ps1 | 7 +- Public/New-TableButtonCSV.ps1 | 9 +- Public/New-TableButtonExcel.ps1 | 9 +- Public/New-TableHeader.ps1 | 11 + Resources/JS/pswritehtml-table-export.js | 91 ++++++ Resources/JS/tabbisNavigation.js | 64 ++++ Tests/ReportCorrectness.Tests.ps1 | 127 ++++++++ readme.md | 21 ++ 40 files changed, 895 insertions(+), 722 deletions(-) create mode 100644 Private/ConvertFrom-HTMLTextLink.ps1 create mode 100644 Private/ConvertTo-HTMLScriptJson.ps1 create mode 100644 Private/Protect-HTMLScriptData.ps1 create mode 100644 Private/Resolve-HTMLMarkdownImages.ps1 delete mode 100644 Private/Tables/Add-TableState.ps1 create mode 100644 Private/Tables/Get-TableExportScript.ps1 create mode 100644 Private/Tables/Get-TableInlineStyles.ps1 create mode 100644 Private/Tables/Set-TableButtons.ps1 create mode 100644 Resources/JS/pswritehtml-table-export.js create mode 100644 Resources/JS/tabbisNavigation.js create mode 100644 Tests/ReportCorrectness.Tests.ps1 diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 13f3ef8a..ae144b09 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -4,6 +4,19 @@ Unfortunetly some code is very old, some code doesn't serve it's purpose anymore, and requires heavy changes that may have an impact on already deployed code. Please make sure to read changes before updating, as we're undergoing some breaking changes. +## 1.42.0 + +- Table exports support explicit row scopes with `-ExportScope`. Excel retains long numeric identifiers as text and supports named `-TextColumns`. +- CSV exports quote fields and protect formula-like text. `New-TableButtonCSV -RawData` retains those values for programmatic consumers. +- Column filters preserve header names, restore saved searches, and follow column visibility. Search panes support named column selection with `-SearchPaneColumns`. +- Row grouping supports multiple levels, independent collapse state, and responsive child rows. +- Inline table conditions can read excluded helper properties, and table rendering preserves the caller's arrays and dates. +- Nested tabs initialize their tables correctly and support deep links and keyboard navigation. Top menu headings follow their configured destinations. +- Markdown preserves backslashes and multiline content, embeds relative local images, and supports `-ImageBase` and `-EmbedImages`. +- Text links support parenthesized labels and nested parentheses in URLs. Merged table titles and column names support independent alignment. +- Chart and widget serialization preserves quoted strings and keeps data containing HTML script delimiters inside its script value. Ajax table files use UTF-8 on both PowerShell runtimes. +- Selected-row hover backgrounds apply to odd and even rows. + ## 1.36.0 ### What's new - Improvements to null handlings in New-HTMLTable @@ -1170,4 +1183,4 @@ New-HTML -TitleText 'Title' -Online -FilePath $PSScriptRoot\Example-TableColumnV ## 0.0.33 - 2019.05.28 - New-HTMLTable - Sorting ordered for DateTime - PR by Ferdi Weiner (ferwe) - - Removed New-HTMLChart temporary as it will be rebuilt \ No newline at end of file + - Removed New-HTMLChart temporary as it will be rebuilt diff --git a/Private/ChartsAll/New-ApexChart.ps1 b/Private/ChartsAll/New-ApexChart.ps1 index 02307d07..7c2ce5a7 100644 --- a/Private/ChartsAll/New-ApexChart.ps1 +++ b/Private/ChartsAll/New-ApexChart.ps1 @@ -1,4 +1,4 @@ -function New-ApexChart { +function New-ApexChart { <# .SYNOPSIS Creates a new ApexChart with the specified options and events. @@ -53,19 +53,19 @@ function New-ApexChart { # Convert Dictionary to JSON and return chart within SCRIPT tag # Make sure to return with additional empty string Remove-EmptyValue -Hashtable $Options -Recursive -Rerun 2 - $JSON = $Options | ConvertTo-JsonLiteral -Depth 5 -AdvancedReplace @{ '.' = '\.'; '$' = '\$' } - # replaces stuff for TImeLineCharts - $JSON = $JSON.Replace('"new Date(', 'new Date(').Replace(').getTime()"', ').getTime()') + $JSON = $Options | ConvertTo-HTMLScriptJson -Depth 20 # We replace Events on JSON because there's no other way that I can think of if ($Options.chart.events) { - $JSON = $JSON -replace ('"events":"EventsReplaceMe"', $Events) + $JSON = [regex]::Replace($JSON, '"events"\s*:\s*"EventsReplaceMe"', { $Events }) } - $JSON = $JSON | ForEach-Object { [System.Text.RegularExpressions.Regex]::Unescape($_) } - "var options = $JSON" - "var chart = new ApexCharts(document.querySelector('#$ID'), + # Timeline producers return date expressions as data. Parse their date + # argument without evaluating text or unescaping the whole JSON object. + 'if (options.chart.type === "rangeBar") { options.series.forEach(function (series) { series.data.forEach(function (point) { if (Array.isArray(point.y)) { point.y = point.y.map(function (value) { var match = typeof value === "string" && /^new Date\(''([\s\S]*)''\)\.getTime\(\)$/.exec(value); return match ? new Date(match[1]).getTime() : value; }); } }); }); }' + $IDJson = ConvertTo-HTMLScriptJson -InputObject $Options.chart.id -Compress + "var chart = new ApexCharts(document.getElementById($IDJson), options );" "chart.render();" @@ -73,4 +73,4 @@ function New-ApexChart { $Div # we need to move it to the end of the code therefore using additional vesel $Script:HTMLSchema.Charts.Add($Script) -} \ No newline at end of file +} diff --git a/Private/ConvertFrom-HTMLTextLink.ps1 b/Private/ConvertFrom-HTMLTextLink.ps1 new file mode 100644 index 00000000..837756b9 --- /dev/null +++ b/Private/ConvertFrom-HTMLTextLink.ps1 @@ -0,0 +1,13 @@ +function ConvertFrom-HTMLTextLink { + <# + .SYNOPSIS + Converts inline text links with independently captured labels and balanced destinations. + #> + [CmdletBinding()] + param([AllowEmptyString()][string] $Text) + $Pattern = '\[(?