From 725dda80c9f7bdcdc5cc1bea0fb4e5077a2a3816 Mon Sep 17 00:00:00 2001 From: leoars <6502186+leoars@users.noreply.github.com> Date: Sun, 8 Nov 2026 23:32:22 -0300 Subject: [PATCH] =?UTF-8?q?[Claude]=20Prepara=20a=20v0.1.0-alpha.5=20com?= =?UTF-8?q?=20diagramas,=20Query=20Designer,=20IntelliSense=20e=20licen?= =?UTF-8?q?=C3=A7a=20Apache-2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTING.md | 2 +- CONTRIBUTING.pt-BR.md | 2 +- Directory.Build.props | 2 +- LICENSE | 223 ++- NOTICE | 7 + README.md | 42 +- README.pt-BR.md | 42 +- SECURITY.md | 2 +- SECURITY.pt-BR.md | 2 +- THIRD-PARTY-NOTICES.md | 2 + docs/assets/README.md | 4 + docs/assets/pgms-diagram.png | Bin 0 -> 30429 bytes docs/assets/pgms-intellisense.png | Bin 0 -> 31676 bytes docs/assets/pgms-query-designer.png | Bin 0 -> 30186 bytes docs/en/README.md | 2 +- docs/en/distribution.md | 2 +- docs/en/getting-started.md | 4 +- docs/en/graphical-installer.md | 2 +- docs/en/licensing.md | 4 +- docs/en/public-readiness.md | 2 +- docs/en/release-notes.md | 43 +- docs/en/user-guide.md | 16 + docs/en/validation.md | 6 +- docs/licenses/Anthropic.txt | 220 +++ docs/licenses/dotnet-extensions.txt | 25 + docs/pt-BR/README.md | 2 +- docs/pt-BR/distribution.md | 2 +- docs/pt-BR/getting-started.md | 4 +- docs/pt-BR/graphical-installer.md | 2 +- docs/pt-BR/licensing.md | 4 +- docs/pt-BR/public-readiness.md | 2 +- docs/pt-BR/release-notes.md | 53 +- docs/pt-BR/user-guide.md | 16 + docs/pt-BR/validation.md | 6 +- installer/release.json | 8 +- scripts/Publish.ps1 | 2 +- scripts/Test-Integration.ps1 | 10 +- src/PGMS.Desktop/AboutWindow.xaml | 21 +- src/PGMS.Desktop/AboutWindow.xaml.cs | 57 +- src/PGMS.Desktop/AiProviderClient.cs | 70 + src/PGMS.Desktop/AiQueryDialog.xaml | 15 + src/PGMS.Desktop/AiQueryDialog.xaml.cs | 101 ++ src/PGMS.Desktop/AiQueryGenerator.cs | 135 ++ src/PGMS.Desktop/AiSettings.cs | 106 ++ src/PGMS.Desktop/AiSettingsDialog.xaml | 15 + src/PGMS.Desktop/AiSettingsDialog.xaml.cs | 132 ++ src/PGMS.Desktop/BuildInfo.cs | 2 +- src/PGMS.Desktop/CatalogIconConverter.cs | 20 +- src/PGMS.Desktop/ChangeScriptDialog.xaml | 13 + src/PGMS.Desktop/ChangeScriptDialog.xaml.cs | 28 + .../CheckConstraintDialog.xaml.cs | 4 +- src/PGMS.Desktop/ConnectionDialog.xaml | 5 +- src/PGMS.Desktop/ConnectionDialog.xaml.cs | 83 +- src/PGMS.Desktop/ConnectionProfiles.cs | 106 +- src/PGMS.Desktop/DatabaseDiagramModel.cs | 742 +++++++++ .../DatabaseDiagramView.Editing.cs | 512 +++++++ src/PGMS.Desktop/DatabaseDiagramView.xaml | 60 + src/PGMS.Desktop/DatabaseDiagramView.xaml.cs | 1351 +++++++++++++++++ src/PGMS.Desktop/DesignerObjectKinds.cs | 98 ++ src/PGMS.Desktop/DesignerObjectsDialog.xaml | 22 + .../DesignerObjectsDialog.xaml.cs | 54 + src/PGMS.Desktop/DesignerPropertyGrid.cs | 140 ++ src/PGMS.Desktop/DiagramDialogs.cs | 238 +++ src/PGMS.Desktop/EditRowsView.xaml | 46 + src/PGMS.Desktop/EditRowsView.xaml.cs | 300 ++++ src/PGMS.Desktop/EnvironmentOptions.cs | 51 + src/PGMS.Desktop/ExecutionPlanDocument.cs | 54 + src/PGMS.Desktop/ExecutionPlanView.cs | 412 +++++ src/PGMS.Desktop/ExplorerMenus.cs | 305 ++++ src/PGMS.Desktop/ExplorerToolbar.cs | 94 ++ src/PGMS.Desktop/FilterSettingsDialog.xaml | 22 + src/PGMS.Desktop/FilterSettingsDialog.xaml.cs | 55 + src/PGMS.Desktop/ForeignKeyDialog.xaml.cs | 5 +- src/PGMS.Desktop/ForeignKeyScanWindow.xaml | 32 + src/PGMS.Desktop/ForeignKeyScanWindow.xaml.cs | 146 ++ src/PGMS.Desktop/HandCursors.cs | 110 ++ src/PGMS.Desktop/LocalServerServices.cs | 155 ++ src/PGMS.Desktop/MainWindow.Close.cs | 27 +- src/PGMS.Desktop/MainWindow.Databases.cs | 93 ++ src/PGMS.Desktop/MainWindow.Diagrams.cs | 256 ++++ src/PGMS.Desktop/MainWindow.QueryDesigner.cs | 39 + src/PGMS.Desktop/MainWindow.QueryMenu.cs | 182 +++ src/PGMS.Desktop/MainWindow.Results.cs | 142 ++ src/PGMS.Desktop/MainWindow.ViewDesigners.cs | 69 + src/PGMS.Desktop/MainWindow.xaml | 108 +- src/PGMS.Desktop/MainWindow.xaml.cs | 347 ++++- .../ObjectPropertiesDialog.xaml.cs | 4 +- src/PGMS.Desktop/OptionsDialog.xaml | 61 + src/PGMS.Desktop/OptionsDialog.xaml.cs | 68 + src/PGMS.Desktop/PGMS.Desktop.csproj | 1 + src/PGMS.Desktop/PsqlLauncher.cs | 43 + src/PGMS.Desktop/QueryDesignerControl.cs | 963 ++++++++++++ src/PGMS.Desktop/QueryDesignerDialog.cs | 102 ++ src/PGMS.Desktop/QueryOptions.cs | 29 + src/PGMS.Desktop/QueryOptionsDialog.xaml | 23 + src/PGMS.Desktop/QueryOptionsDialog.xaml.cs | 38 + src/PGMS.Desktop/QueryOptionsPages.xaml | 72 + src/PGMS.Desktop/QueryOptionsPages.xaml.cs | 107 ++ src/PGMS.Desktop/QueryView.Completion.cs | 143 ++ src/PGMS.Desktop/QueryView.Options.cs | 68 + src/PGMS.Desktop/QueryView.Paging.cs | 190 +++ src/PGMS.Desktop/QueryView.Plan.cs | 47 +- src/PGMS.Desktop/QueryView.QueryMenu.cs | 121 ++ src/PGMS.Desktop/QueryView.Results.cs | 173 +++ src/PGMS.Desktop/QueryView.Session.cs | 20 + src/PGMS.Desktop/QueryView.xaml | 37 +- src/PGMS.Desktop/QueryView.xaml.cs | 118 +- src/PGMS.Desktop/RegisteredServersHost.cs | 78 + src/PGMS.Desktop/RegisteredServersView.xaml | 24 + .../RegisteredServersView.xaml.cs | 185 +++ src/PGMS.Desktop/RelationEditDialog.xaml.cs | 4 +- src/PGMS.Desktop/ReportView.xaml | 23 + src/PGMS.Desktop/ReportView.xaml.cs | 115 ++ src/PGMS.Desktop/Resources/Shell.xaml | 318 +++- src/PGMS.Desktop/ResultExportSnapshot.cs | 9 +- src/PGMS.Desktop/ResultGridCopy.cs | 4 +- src/PGMS.Desktop/ResultGridStyle.cs | 82 + src/PGMS.Desktop/RoleAttributeDialog.xaml | 13 +- src/PGMS.Desktop/RoleAttributeDialog.xaml.cs | 29 +- src/PGMS.Desktop/RoleMembershipDialog.xaml.cs | 4 +- src/PGMS.Desktop/RolePasswordDialog.xaml | 4 +- src/PGMS.Desktop/RolePasswordDialog.xaml.cs | 25 +- src/PGMS.Desktop/RolePasswordInput.cs | 57 + src/PGMS.Desktop/SequenceDialog.xaml.cs | 4 +- src/PGMS.Desktop/ServerGroupDialog.xaml | 12 + src/PGMS.Desktop/ServerGroupDialog.xaml.cs | 24 + src/PGMS.Desktop/ServerPropertiesDialog.xaml | 21 + .../ServerPropertiesDialog.xaml.cs | 67 + src/PGMS.Desktop/ServerTlsDialog.xaml | 26 + src/PGMS.Desktop/ServerTlsDialog.xaml.cs | 122 ++ .../TableConstraintDialog.xaml.cs | 4 +- src/PGMS.Desktop/TableDesignerRows.cs | 176 +++ src/PGMS.Desktop/TableDesignerView.xaml | 115 ++ src/PGMS.Desktop/TableDesignerView.xaml.cs | 419 +++++ src/PGMS.Desktop/TablePropertiesDialog.xaml | 28 +- .../TablePropertiesDialog.xaml.cs | 229 ++- src/PGMS.Desktop/ViewDesignerView.cs | 119 ++ src/PGMS.Desktop/ViewModels/CatalogFilter.cs | 17 + src/PGMS.Desktop/ViewModels/CatalogNode.cs | 24 +- src/PGMS.Desktop/WindowWorkArea.cs | 10 +- src/PGMS.Desktop/packages.lock.json | 14 + src/PGMS.PostgreSql/AdministrativeEdits.cs | 3 +- src/PGMS.PostgreSql/CatalogService.cs | 28 +- src/PGMS.PostgreSql/ClientStatistics.cs | 106 ++ src/PGMS.PostgreSql/DatabaseDiagrams.cs | 355 +++++ src/PGMS.PostgreSql/ExecutionPlanModel.cs | 284 ++++ src/PGMS.PostgreSql/ForeignKeyScan.cs | 200 +++ src/PGMS.PostgreSql/QueryActualPlans.cs | 81 + src/PGMS.PostgreSql/QueryDesign.cs | 874 +++++++++++ src/PGMS.PostgreSql/QueryExecutionOptions.cs | 23 + src/PGMS.PostgreSql/QueryPlanFiles.cs | 17 + src/PGMS.PostgreSql/QueryPlans.cs | 1 + src/PGMS.PostgreSql/QuerySessionInfo.cs | 97 ++ src/PGMS.PostgreSql/QueryStreaming.cs | 102 +- src/PGMS.PostgreSql/ResultCopyText.cs | 7 +- src/PGMS.PostgreSql/ResultJson.cs | 38 + src/PGMS.PostgreSql/ResultPages.cs | 120 ++ src/PGMS.PostgreSql/RolePasswords.cs | 25 +- src/PGMS.PostgreSql/SchemaContext.cs | 149 ++ src/PGMS.PostgreSql/ServerProperties.cs | 103 ++ src/PGMS.PostgreSql/ServerReports.cs | 255 ++++ src/PGMS.PostgreSql/ServerTls.cs | 278 ++++ src/PGMS.PostgreSql/SqlCompletion.cs | 416 +++++ src/PGMS.PostgreSql/TableDesign.cs | 500 ++++++ src/PGMS.PostgreSql/TableRows.cs | 188 +++ src/PGMS.PostgreSql/TextResults.cs | 184 +++ tests/PGMS.DesktopTests/AboutChecks.cs | 46 + .../PGMS.DesktopTests/ActivityPanelChecks.cs | 4 +- tests/PGMS.DesktopTests/AiQueryChecks.cs | 143 ++ tests/PGMS.DesktopTests/AiSettingsChecks.cs | 146 ++ .../ConnectDialogStateChecks.cs | 83 + .../DatabaseDiagramChecks.cs | 814 ++++++++++ .../PGMS.DesktopTests/DiagramEditingChecks.cs | 282 ++++ .../ExecutionPlanUiChecks.cs | 171 +++ .../ExplorerContextChecks.cs | 17 +- .../ExplorerDisconnectChecks.cs | 41 + .../ExplorerExperienceChecks.cs | 185 ++- tests/PGMS.DesktopTests/ExplorerMenuChecks.cs | 90 ++ .../ExplorerToolbarChecks.cs | 68 + .../PGMS.DesktopTests/FilterSettingsChecks.cs | 66 + .../ForeignKeyScanUiChecks.cs | 73 + .../PGMS.DesktopTests/InspectOnOpenChecks.cs | 45 + .../PGMS.DesktopTests/InspectionEditChecks.cs | 2 +- tests/PGMS.DesktopTests/LocalServiceChecks.cs | 108 ++ .../PGMS.DesktopTests/ObjectPropertyChecks.cs | 5 +- tests/PGMS.DesktopTests/Program.cs | 22 +- .../QueryCloseCommandChecks.cs | 2 +- .../PGMS.DesktopTests/QueryDesignerChecks.cs | 350 +++++ tests/PGMS.DesktopTests/QueryLoadChecks.cs | 17 +- tests/PGMS.DesktopTests/QueryMenuChecks.cs | 207 +++ tests/PGMS.DesktopTests/QueryOptionsChecks.cs | 223 +++ tests/PGMS.DesktopTests/QueryPlanUiChecks.cs | 19 +- .../QueryResultCopyChecks.cs | 3 +- .../PGMS.DesktopTests/QueryStreamingChecks.cs | 8 +- .../RegisteredServersChecks.cs | 140 ++ tests/PGMS.DesktopTests/ReportViewChecks.cs | 78 + tests/PGMS.DesktopTests/ResultPagingChecks.cs | 98 ++ .../ResultsDestinationChecks.cs | 245 +++ .../RolePropertiesPasswordChecks.cs | 115 ++ .../ServerTlsDialogChecks.cs | 77 + .../PGMS.DesktopTests/TableDesignerChecks.cs | 263 ++++ .../TablePropertiesEditChecks.cs | 91 ++ .../PGMS.DesktopTests/TablePropertyChecks.cs | 2 +- .../PGMS.DesktopTests/TreeSelectionChecks.cs | 65 + tests/PGMS.DesktopTests/ViewDesignerChecks.cs | 213 +++ .../WindowPlacementChecks.cs | 93 ++ tests/PGMS.DesktopTests/packages.lock.json | 14 + tests/PGMS.IntegrationTests/DiagramChecks.cs | 188 +++ .../ForeignKeyScanChecks.cs | 111 ++ tests/PGMS.IntegrationTests/Program.cs | 28 +- .../QueryActualPlanChecks.cs | 53 + .../QueryDesignChecks.cs | 205 +++ .../QueryMenuEngineChecks.cs | 53 + .../QueryOptionsEngineChecks.cs | 86 ++ .../PGMS.IntegrationTests/QueryPlanChecks.cs | 1 + .../ResultPagesChecks.cs | 81 + .../ResultsTextChecks.cs | 164 ++ .../SchemaContextChecks.cs | 46 + .../ServerReportChecks.cs | 126 ++ .../PGMS.IntegrationTests/ServerTlsChecks.cs | 86 ++ .../SqlCompletionChecks.cs | 119 ++ .../TableDesignChecks.cs | 166 ++ .../UnicodePasswordChecks.cs | 6 +- 223 files changed, 23038 insertions(+), 429 deletions(-) create mode 100644 NOTICE create mode 100644 docs/assets/pgms-diagram.png create mode 100644 docs/assets/pgms-intellisense.png create mode 100644 docs/assets/pgms-query-designer.png create mode 100644 docs/licenses/Anthropic.txt create mode 100644 docs/licenses/dotnet-extensions.txt create mode 100644 src/PGMS.Desktop/AiProviderClient.cs create mode 100644 src/PGMS.Desktop/AiQueryDialog.xaml create mode 100644 src/PGMS.Desktop/AiQueryDialog.xaml.cs create mode 100644 src/PGMS.Desktop/AiQueryGenerator.cs create mode 100644 src/PGMS.Desktop/AiSettings.cs create mode 100644 src/PGMS.Desktop/AiSettingsDialog.xaml create mode 100644 src/PGMS.Desktop/AiSettingsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/ChangeScriptDialog.xaml create mode 100644 src/PGMS.Desktop/ChangeScriptDialog.xaml.cs create mode 100644 src/PGMS.Desktop/DatabaseDiagramModel.cs create mode 100644 src/PGMS.Desktop/DatabaseDiagramView.Editing.cs create mode 100644 src/PGMS.Desktop/DatabaseDiagramView.xaml create mode 100644 src/PGMS.Desktop/DatabaseDiagramView.xaml.cs create mode 100644 src/PGMS.Desktop/DesignerObjectKinds.cs create mode 100644 src/PGMS.Desktop/DesignerObjectsDialog.xaml create mode 100644 src/PGMS.Desktop/DesignerObjectsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/DesignerPropertyGrid.cs create mode 100644 src/PGMS.Desktop/DiagramDialogs.cs create mode 100644 src/PGMS.Desktop/EditRowsView.xaml create mode 100644 src/PGMS.Desktop/EditRowsView.xaml.cs create mode 100644 src/PGMS.Desktop/EnvironmentOptions.cs create mode 100644 src/PGMS.Desktop/ExecutionPlanDocument.cs create mode 100644 src/PGMS.Desktop/ExecutionPlanView.cs create mode 100644 src/PGMS.Desktop/ExplorerMenus.cs create mode 100644 src/PGMS.Desktop/ExplorerToolbar.cs create mode 100644 src/PGMS.Desktop/FilterSettingsDialog.xaml create mode 100644 src/PGMS.Desktop/FilterSettingsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/ForeignKeyScanWindow.xaml create mode 100644 src/PGMS.Desktop/ForeignKeyScanWindow.xaml.cs create mode 100644 src/PGMS.Desktop/HandCursors.cs create mode 100644 src/PGMS.Desktop/LocalServerServices.cs create mode 100644 src/PGMS.Desktop/MainWindow.Databases.cs create mode 100644 src/PGMS.Desktop/MainWindow.Diagrams.cs create mode 100644 src/PGMS.Desktop/MainWindow.QueryDesigner.cs create mode 100644 src/PGMS.Desktop/MainWindow.QueryMenu.cs create mode 100644 src/PGMS.Desktop/MainWindow.Results.cs create mode 100644 src/PGMS.Desktop/MainWindow.ViewDesigners.cs create mode 100644 src/PGMS.Desktop/OptionsDialog.xaml create mode 100644 src/PGMS.Desktop/OptionsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/PsqlLauncher.cs create mode 100644 src/PGMS.Desktop/QueryDesignerControl.cs create mode 100644 src/PGMS.Desktop/QueryDesignerDialog.cs create mode 100644 src/PGMS.Desktop/QueryOptions.cs create mode 100644 src/PGMS.Desktop/QueryOptionsDialog.xaml create mode 100644 src/PGMS.Desktop/QueryOptionsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/QueryOptionsPages.xaml create mode 100644 src/PGMS.Desktop/QueryOptionsPages.xaml.cs create mode 100644 src/PGMS.Desktop/QueryView.Completion.cs create mode 100644 src/PGMS.Desktop/QueryView.Paging.cs create mode 100644 src/PGMS.Desktop/QueryView.QueryMenu.cs create mode 100644 src/PGMS.Desktop/QueryView.Results.cs create mode 100644 src/PGMS.Desktop/RegisteredServersHost.cs create mode 100644 src/PGMS.Desktop/RegisteredServersView.xaml create mode 100644 src/PGMS.Desktop/RegisteredServersView.xaml.cs create mode 100644 src/PGMS.Desktop/ReportView.xaml create mode 100644 src/PGMS.Desktop/ReportView.xaml.cs create mode 100644 src/PGMS.Desktop/ResultGridStyle.cs create mode 100644 src/PGMS.Desktop/RolePasswordInput.cs create mode 100644 src/PGMS.Desktop/ServerGroupDialog.xaml create mode 100644 src/PGMS.Desktop/ServerGroupDialog.xaml.cs create mode 100644 src/PGMS.Desktop/ServerPropertiesDialog.xaml create mode 100644 src/PGMS.Desktop/ServerPropertiesDialog.xaml.cs create mode 100644 src/PGMS.Desktop/ServerTlsDialog.xaml create mode 100644 src/PGMS.Desktop/ServerTlsDialog.xaml.cs create mode 100644 src/PGMS.Desktop/TableDesignerRows.cs create mode 100644 src/PGMS.Desktop/TableDesignerView.xaml create mode 100644 src/PGMS.Desktop/TableDesignerView.xaml.cs create mode 100644 src/PGMS.Desktop/ViewDesignerView.cs create mode 100644 src/PGMS.Desktop/ViewModels/CatalogFilter.cs create mode 100644 src/PGMS.PostgreSql/ClientStatistics.cs create mode 100644 src/PGMS.PostgreSql/DatabaseDiagrams.cs create mode 100644 src/PGMS.PostgreSql/ExecutionPlanModel.cs create mode 100644 src/PGMS.PostgreSql/ForeignKeyScan.cs create mode 100644 src/PGMS.PostgreSql/QueryActualPlans.cs create mode 100644 src/PGMS.PostgreSql/QueryDesign.cs create mode 100644 src/PGMS.PostgreSql/ResultJson.cs create mode 100644 src/PGMS.PostgreSql/ResultPages.cs create mode 100644 src/PGMS.PostgreSql/SchemaContext.cs create mode 100644 src/PGMS.PostgreSql/ServerProperties.cs create mode 100644 src/PGMS.PostgreSql/ServerReports.cs create mode 100644 src/PGMS.PostgreSql/ServerTls.cs create mode 100644 src/PGMS.PostgreSql/SqlCompletion.cs create mode 100644 src/PGMS.PostgreSql/TableDesign.cs create mode 100644 src/PGMS.PostgreSql/TableRows.cs create mode 100644 src/PGMS.PostgreSql/TextResults.cs create mode 100644 tests/PGMS.DesktopTests/AboutChecks.cs create mode 100644 tests/PGMS.DesktopTests/AiQueryChecks.cs create mode 100644 tests/PGMS.DesktopTests/AiSettingsChecks.cs create mode 100644 tests/PGMS.DesktopTests/ConnectDialogStateChecks.cs create mode 100644 tests/PGMS.DesktopTests/DatabaseDiagramChecks.cs create mode 100644 tests/PGMS.DesktopTests/DiagramEditingChecks.cs create mode 100644 tests/PGMS.DesktopTests/ExecutionPlanUiChecks.cs create mode 100644 tests/PGMS.DesktopTests/ExplorerDisconnectChecks.cs create mode 100644 tests/PGMS.DesktopTests/ExplorerMenuChecks.cs create mode 100644 tests/PGMS.DesktopTests/ExplorerToolbarChecks.cs create mode 100644 tests/PGMS.DesktopTests/FilterSettingsChecks.cs create mode 100644 tests/PGMS.DesktopTests/ForeignKeyScanUiChecks.cs create mode 100644 tests/PGMS.DesktopTests/InspectOnOpenChecks.cs create mode 100644 tests/PGMS.DesktopTests/LocalServiceChecks.cs create mode 100644 tests/PGMS.DesktopTests/QueryDesignerChecks.cs create mode 100644 tests/PGMS.DesktopTests/QueryMenuChecks.cs create mode 100644 tests/PGMS.DesktopTests/QueryOptionsChecks.cs create mode 100644 tests/PGMS.DesktopTests/RegisteredServersChecks.cs create mode 100644 tests/PGMS.DesktopTests/ReportViewChecks.cs create mode 100644 tests/PGMS.DesktopTests/ResultPagingChecks.cs create mode 100644 tests/PGMS.DesktopTests/ResultsDestinationChecks.cs create mode 100644 tests/PGMS.DesktopTests/RolePropertiesPasswordChecks.cs create mode 100644 tests/PGMS.DesktopTests/ServerTlsDialogChecks.cs create mode 100644 tests/PGMS.DesktopTests/TableDesignerChecks.cs create mode 100644 tests/PGMS.DesktopTests/TablePropertiesEditChecks.cs create mode 100644 tests/PGMS.DesktopTests/TreeSelectionChecks.cs create mode 100644 tests/PGMS.DesktopTests/ViewDesignerChecks.cs create mode 100644 tests/PGMS.DesktopTests/WindowPlacementChecks.cs create mode 100644 tests/PGMS.IntegrationTests/DiagramChecks.cs create mode 100644 tests/PGMS.IntegrationTests/ForeignKeyScanChecks.cs create mode 100644 tests/PGMS.IntegrationTests/QueryActualPlanChecks.cs create mode 100644 tests/PGMS.IntegrationTests/QueryDesignChecks.cs create mode 100644 tests/PGMS.IntegrationTests/QueryMenuEngineChecks.cs create mode 100644 tests/PGMS.IntegrationTests/QueryOptionsEngineChecks.cs create mode 100644 tests/PGMS.IntegrationTests/ResultPagesChecks.cs create mode 100644 tests/PGMS.IntegrationTests/ResultsTextChecks.cs create mode 100644 tests/PGMS.IntegrationTests/SchemaContextChecks.cs create mode 100644 tests/PGMS.IntegrationTests/ServerReportChecks.cs create mode 100644 tests/PGMS.IntegrationTests/ServerTlsChecks.cs create mode 100644 tests/PGMS.IntegrationTests/SqlCompletionChecks.cs create mode 100644 tests/PGMS.IntegrationTests/TableDesignChecks.cs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 200e0f0..2aa72e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,6 @@ Changes to public documentation must update both `docs/en` and `docs/pt-BR` (and New behavior, administration or UI changes should include proportional validation. Do not claim SSMS parity or certify platforms based only on synthetic tests. Desktop and database checks require Windows and PostgreSQL tools; state any checks you could not run. -PGMS's original code and documentation use the [MIT license](LICENSE); third-party components retain their own licenses. Submit only material you may contribute under these terms. Never include proprietary binaries, copied vendor icons or secrets. Follow the [security reporting policy](SECURITY.md) for vulnerabilities. +PGMS's original code and documentation use the [Apache-2.0 license](LICENSE) (releases through 0.1.0-alpha.4 remain under MIT); third-party components retain their own licenses. Submit only material you may contribute under these terms. Never include proprietary binaries, copied vendor icons or secrets. Follow the [security reporting policy](SECURITY.md) for vulnerabilities. Codex-created commit messages must start with `[Codex]`, as required by the repository's author. This prefix is not required of human contributors. diff --git a/CONTRIBUTING.pt-BR.md b/CONTRIBUTING.pt-BR.md index 3e5a02b..551e62e 100644 --- a/CONTRIBUTING.pt-BR.md +++ b/CONTRIBUTING.pt-BR.md @@ -10,6 +10,6 @@ Mudanças na documentação pública devem atualizar `docs/en` e `docs/pt-BR` e Novos comportamentos, administração e mudanças de interface precisam de validação proporcional. Não declare paridade com SSMS ou certificação de plataformas somente por testes sintéticos. As verificações de desktop e banco exigem Windows e ferramentas PostgreSQL; informe o que não conseguiu executar. -O código e a documentação próprios do PGMS usam a [licença MIT](LICENSE); componentes de terceiros mantêm suas licenças. Envie somente material que possa contribuir nesses termos. Nunca inclua binários proprietários, ícones copiados de fornecedores ou segredos. Siga a [política de segurança](SECURITY.pt-BR.md) para vulnerabilidades. +O código e a documentação próprios do PGMS usam a [licença Apache-2.0](LICENSE) (as versões até 0.1.0-alpha.4 continuam sob MIT); componentes de terceiros mantêm suas licenças. Envie somente material que possa contribuir nesses termos. Nunca inclua binários proprietários, ícones copiados de fornecedores ou segredos. Siga a [política de segurança](SECURITY.pt-BR.md) para vulnerabilidades. Mensagens de commits criados pelo Codex devem começar com `[Codex]`, conforme preferência do autor do repositório. Esse prefixo não é exigido de contribuidores humanos. diff --git a/Directory.Build.props b/Directory.Build.props index 0b4fdb5..e4ee6f4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 0.1.0-alpha.4 + 0.1.0-alpha.5 enable enable true diff --git a/LICENSE b/LICENSE index dde7218..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,202 @@ -MIT License - -Copyright (c) 2026 Leonardo Santos - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..875cf6b --- /dev/null +++ b/NOTICE @@ -0,0 +1,7 @@ +Postgres Management Studio (PGMS) +Copyright 2026 Leonardo Santos + +Created and maintained by Leonardo Santos +https://github.com/leoars + +Third-party components keep their own licenses; see THIRD-PARTY-NOTICES.md. diff --git a/README.md b/README.md index f725e8b..43cb58b 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,41 @@ English | [Português (Brasil)](README.pt-BR.md) -[![Build](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml/badge.svg)](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml) [![Pre-release](https://img.shields.io/github/v/release/leoars/PostgresManagementStudio?include_prereleases&label=pre-release)](https://github.com/leoars/PostgresManagementStudio/releases) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Build](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml/badge.svg)](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml) [![Pre-release](https://img.shields.io/github/v/release/leoars/PostgresManagementStudio?include_prereleases&label=pre-release)](https://github.com/leoars/PostgresManagementStudio/releases) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) -**The SQL Server Management Studio experience, for PostgreSQL.** A native Windows client with Object Explorer, F5 to run, execution plans, session monitoring and backup/restore, built for people who already think in SSMS. +**The SQL Server Management Studio experience, for PostgreSQL.** A native Windows client with **database diagrams**, a **visual query designer** and **context-aware IntelliSense**, plus Object Explorer, F5 to run, execution plans, session monitoring and backup/restore, built for people who already think in SSMS. -**[Download v0.1.0-alpha.4 for Windows x64](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4)** · Graphical installer (EN/pt-BR) or portable ZIP, .NET runtime included · Works with PostgreSQL 16–18 +**[Download v0.1.0-alpha.5 for Windows x64](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5)** · Graphical installer (EN/pt-BR) or portable ZIP, .NET runtime included · Works with PostgreSQL 16–18 ![PGMS editor, Object Explorer and query results](docs/assets/pgms-results-m959.jpg) > Early pre-release. Querying, browsing and monitoring are the core of this alpha; administration and backup run through reviewable SQL and the official PostgreSQL tools. Full SSMS parity is not claimed. See [known limits](docs/en/validation.md) and [release notes](docs/en/release-notes.md). +## Highlights + +### Database diagrams + +![A database diagram in PGMS with eight tables and their foreign keys](docs/assets/pgms-diagram.png) + +See your schema the way you see it in SSMS. Add tables and their related tables, drag one column onto another to create a foreign key, change columns and primary keys inside the diagram, and let **Arrange Tables** lay everything out. Every change to the database is shown as a SQL script for review first. Diagrams are saved on the server, in a small `pgms` schema that PGMS asks permission to create. + +### Visual query designer + +![The Query Designer with the Diagram, Criteria and SQL panes](docs/assets/pgms-query-designer.png) + +Build queries by clicking instead of typing. **Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) opens the statement under the cursor in synchronized Diagram, Criteria and SQL panes: tick columns, set filters and sort order, and joins come from your foreign keys. Change the type to Update, Delete, Insert or Make Table. It only writes SQL into your editor and never runs it. `UNION` and `WITH` open in the SQL pane only. + +### IntelliSense that knows where you are + +![IntelliSense after JOIN suggesting a complete join from a foreign key](docs/assets/pgms-intellisense.png) + +Press `Ctrl+Space` and get what fits that position. After `FROM`: tables, views and table functions, found by name across all your schemas. After `JOIN`: the whole join from your foreign keys, such as `orders o ON o.customer_id = c.id`. After an alias: its columns. Typing ignores accents, so `usuar` finds `Usuários`. Parameter Info, Quick Info and CTE columns are not available yet. + +### Also in PGMS + +- **Generate SQL with AI.** Describe a query and review the SQL before it reaches the editor, using Anthropic, OpenAI or a local Ollama with your own key. Your request and the database structure go to the provider you configure; table data is never read or sent. +- **Configure Server TLS.** A guided setup that installs a certificate and turns on TLS, restoring the previous settings if it fails. Requires a superuser connection to a server running on Windows. + ## Why PGMS - **Feels like SSMS.** Object Explorer, query tabs with their own sessions, Results/Messages, F5 and the shortcuts you already use. @@ -22,9 +47,10 @@ English | [Português (Brasil)](README.pt-BR.md) ## Features -- SQL editor: highlighting, find/replace, multiple tabs, save/load and encrypted draft recovery. -- Independent PostgreSQL sessions, execute/cancel, Results/Messages, bounded result grids, copy and CSV/JSON export. -- Object Explorer, inspection, estimated/analyzed query plans and session configuration. +- SQL editor: highlighting, context-aware IntelliSense, find/replace, multiple tabs, save/load and encrypted draft recovery. +- Database diagrams, Table Designer, View Designer and Query Designer. +- Independent PostgreSQL sessions, execute/cancel, Results/Messages, result grids in pages of 100,000 rows (configurable), results to text or file, copy and CSV/JSON export. +- Object Explorer, inspection, graphical execution plans (estimated and actual) and session configuration. - Reviewed SQL administration for supported databases, schemas, tables, columns, identity, indexes, constraints, sequences, roles and privileges. - Session/blocker monitoring, with distinct query cancellation and session termination. - Logical backup/restore through external PostgreSQL tools: custom, tar, SQL and directory formats, plus reviewed global operations. @@ -46,7 +72,7 @@ Get-FileHash .\PGMS-* -Algorithm SHA256 Compare the hashes with `SHA256SUMS.txt` in the release. Starting with v0.1.0-alpha.2 the assets are built by the [release workflow](.github/workflows/release.yml) on GitHub Actions and carry a build provenance attestation, so you can also confirm that the ZIP or installer came from that workflow and this repository (requires the [GitHub CLI](https://cli.github.com/)): ```powershell -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` v0.1.0-alpha.1 was built on the maintainer's machine and has checksums only. Code signing through the SignPath Foundation open source program is planned. @@ -83,4 +109,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) and the [code of conduct](CODE_OF_CONDUCT ## License -PGMS's original code and documentation use [MIT](LICENSE). Third-party components and the PostgreSQL elephant retain their own licenses and trademark terms; see [third-party notices](THIRD-PARTY-NOTICES.md). PGMS is independent, without endorsement by Microsoft or the PostgreSQL project. SSMS is a reference, not a distributed dependency. +PGMS is created and maintained by [Leonardo Santos](https://github.com/leoars). Its original code and documentation use [Apache-2.0](LICENSE): free for personal and business use, keeping the copyright and the credits in [NOTICE](NOTICE). Releases through 0.1.0-alpha.4 remain under MIT. Third-party components and the PostgreSQL elephant retain their own licenses and trademark terms; see [third-party notices](THIRD-PARTY-NOTICES.md). PGMS is independent, without endorsement by Microsoft or the PostgreSQL project. SSMS is a reference, not a distributed dependency. diff --git a/README.pt-BR.md b/README.pt-BR.md index fd94602..535e818 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -2,16 +2,41 @@ [English](README.md) | Português (Brasil) -[![Build](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml/badge.svg)](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml) [![Pré-release](https://img.shields.io/github/v/release/leoars/PostgresManagementStudio?include_prereleases&label=pr%C3%A9-release)](https://github.com/leoars/PostgresManagementStudio/releases) [![Licença: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Build](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml/badge.svg)](https://github.com/leoars/PostgresManagementStudio/actions/workflows/build.yml) [![Pré-release](https://img.shields.io/github/v/release/leoars/PostgresManagementStudio?include_prereleases&label=pr%C3%A9-release)](https://github.com/leoars/PostgresManagementStudio/releases) [![Licença: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) -**A experiência do SQL Server Management Studio, para PostgreSQL.** Cliente nativo Windows com Object Explorer, F5 para executar, planos de execução, monitor de sessões e backup/restore, feito para quem já pensa em SSMS. +**A experiência do SQL Server Management Studio, para PostgreSQL.** Cliente nativo Windows com **diagramas de banco**, **Query Designer visual** e **IntelliSense por contexto**, além de Object Explorer, F5 para executar, planos de execução, monitor de sessões e backup/restore, feito para quem já pensa em SSMS. -**[Baixar v0.1.0-alpha.4 para Windows x64](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4)** · Instalador gráfico (EN/pt-BR) ou ZIP portátil, runtime .NET incluído · Funciona com PostgreSQL 16 a 18 +**[Baixar v0.1.0-alpha.5 para Windows x64](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5)** · Instalador gráfico (EN/pt-BR) ou ZIP portátil, runtime .NET incluído · Funciona com PostgreSQL 16 a 18 ![Editor, Object Explorer e resultados do PGMS](docs/assets/pgms-results-m959.jpg) > Pré-release inicial. Consultas, navegação e monitoramento são o núcleo desta alpha; administração e backup usam SQL revisável e as ferramentas oficiais do PostgreSQL. Não se declara paridade integral com SSMS. Veja os [limites conhecidos](docs/pt-BR/validation.md) e as [notas da versão](docs/pt-BR/release-notes.md). +## Destaques + +### Diagramas de banco de dados + +![Um diagrama de banco no PGMS com oito tabelas e suas chaves estrangeiras](docs/assets/pgms-diagram.png) + +Veja o seu schema como no SSMS. Adicione tabelas e as tabelas relacionadas, arraste uma coluna sobre outra para criar uma chave estrangeira, altere colunas e chaves primárias dentro do diagrama e deixe o **Arrange Tables** organizar tudo. Toda alteração no banco aparece antes como script SQL para revisão. Os diagramas ficam salvos no servidor, num pequeno schema `pgms` que o PGMS pede permissão para criar. + +### Query Designer visual + +![O Query Designer com os painéis Diagram, Criteria e SQL](docs/assets/pgms-query-designer.png) + +Monte consultas clicando, em vez de digitar. **Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) abre a instrução sob o cursor nos painéis Diagram, Criteria e SQL, sempre sincronizados: marque colunas, defina filtros e ordenação, e as junções vêm das suas chaves estrangeiras. Mude o tipo para Update, Delete, Insert ou Make Table. Ele só escreve SQL no editor e nunca executa nada. `UNION` e `WITH` abrem apenas no painel SQL. + +### IntelliSense que sabe onde você está + +![IntelliSense depois de JOIN sugerindo uma junção completa a partir de uma chave estrangeira](docs/assets/pgms-intellisense.png) + +Aperte `Ctrl+Space` e receba o que cabe naquela posição. Depois de `FROM`: tabelas, views e funções de tabela, encontradas pelo nome em todos os seus schemas. Depois de `JOIN`: a junção inteira a partir das chaves estrangeiras, como `orders o ON o.customer_id = c.id`. Depois de um alias: as colunas dele. A busca ignora acentos, então `usuar` encontra `Usuários`. Parameter Info, Quick Info e colunas de CTE ainda não existem. + +### Também no PGMS + +- **Gerar SQL com IA.** Descreva a consulta e revise o SQL antes de ele ir para o editor, com Anthropic, OpenAI ou um Ollama local, usando a sua própria chave. O pedido e a estrutura do banco vão para o provedor que você configurar; dados das tabelas nunca são lidos nem enviados. +- **Configure Server TLS.** Assistente que instala um certificado e liga o TLS, restaurando a configuração anterior se algo falhar. Exige conexão de superusuário a um servidor em Windows. + ## Por que o PGMS - **Parece o SSMS.** Object Explorer, abas de consulta com sessão própria, Results/Messages, F5 e os atalhos que você já usa. @@ -22,9 +47,10 @@ ## Funcionalidades -- Editor SQL: destaque, busca/substituição, múltiplas abas, abrir/salvar e recuperação criptografada de rascunhos. -- Sessões PostgreSQL independentes, executar/cancelar, Results/Messages, grade com limites, cópia e exportação CSV/JSON. -- Object Explorer, inspeção, planos estimados/analisados e configuração da sessão. +- Editor SQL: destaque, IntelliSense por contexto, busca/substituição, múltiplas abas, abrir/salvar e recuperação criptografada de rascunhos. +- Diagramas de banco, Table Designer, View Designer e Query Designer. +- Sessões PostgreSQL independentes, executar/cancelar, Results/Messages, grade em páginas de 100.000 linhas (configurável), resultados em texto ou arquivo, cópia e exportação CSV/JSON. +- Object Explorer, inspeção, planos de execução gráficos (estimados e reais) e configuração da sessão. - Administração com SQL revisável nos casos suportados de bancos, schemas, tabelas, colunas, identity, índices, constraints, sequences, roles e privilégios. - Monitor de sessões/bloqueadores, com cancelamento de consulta e encerramento de sessão distintos. - Backup/restore lógico por ferramentas externas PostgreSQL: custom, tar, SQL e diretório, além de operações globais revisadas. @@ -46,7 +72,7 @@ Get-FileHash .\PGMS-* -Algorithm SHA256 Compare os hashes com o `SHA256SUMS.txt` da release. A partir da v0.1.0-alpha.2 os assets são compilados pelo [workflow de release](.github/workflows/release.yml) no GitHub Actions e trazem atestado de proveniência de build, então você também pode confirmar que o ZIP ou o instalador saiu desse workflow e deste repositório (exige o [GitHub CLI](https://cli.github.com/)): ```powershell -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` A v0.1.0-alpha.1 foi compilada na máquina do mantenedor e tem apenas checksums. A assinatura de código pelo programa open source da SignPath Foundation está planejada. @@ -83,4 +109,4 @@ Veja [CONTRIBUTING.pt-BR.md](CONTRIBUTING.pt-BR.md) e o [código de conduta](COD ## Licença -Código e documentação próprios do PGMS usam a [MIT](LICENSE). Componentes de terceiros e o elefante PostgreSQL mantêm suas licenças e condições de marca; veja os [avisos de terceiros](THIRD-PARTY-NOTICES.md). O PGMS é independente, sem endosso da Microsoft ou do projeto PostgreSQL. SSMS é referência, sem dependência distribuída. +O PGMS é criado e mantido por [Leonardo Santos](https://github.com/leoars). Código e documentação próprios usam a [Apache-2.0](LICENSE): uso livre pessoal e em empresas, mantendo o copyright e os créditos do [NOTICE](NOTICE). As versões até 0.1.0-alpha.4 continuam sob MIT. Componentes de terceiros e o elefante PostgreSQL mantêm suas licenças e condições de marca; veja os [avisos de terceiros](THIRD-PARTY-NOTICES.md). O PGMS é independente, sem endosso da Microsoft ou do projeto PostgreSQL. SSMS é referência, sem dependência distribuída. diff --git a/SECURITY.md b/SECURITY.md index 2a086c6..c40d4fe 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ English | [Português (Brasil)](SECURITY.pt-BR.md) -PGMS is in development. There is no published supported release series or guaranteed response time. Current development and the v0.1.0-alpha.4 pre-release are the starting points for investigation; historical packages do not automatically receive fixes. +PGMS is in development. There is no published supported release series or guaranteed response time. Current development and the v0.1.0-alpha.5 pre-release are the starting points for investigation; historical packages do not automatically receive fixes. Do not disclose an unpatched vulnerability or real credentials in a public issue. Use GitHub's **Report a vulnerability** on this repository if private reporting is enabled. If it is unavailable, open an issue asking the maintainer for a private contact channel without including vulnerability details. Never post database dumps, saved profiles, DPAPI payloads, access tokens or private keys. diff --git a/SECURITY.pt-BR.md b/SECURITY.pt-BR.md index eb0e0cd..edc9b93 100644 --- a/SECURITY.pt-BR.md +++ b/SECURITY.pt-BR.md @@ -2,7 +2,7 @@ [English](SECURITY.md) | Português (Brasil) -O PGMS está em desenvolvimento. Não há série de releases publicada com suporte nem prazo de resposta garantido. O desenvolvimento atual e a pré-release v0.1.0-alpha.4 são o ponto de partida para investigação; pacotes históricos não recebem correções automaticamente. +O PGMS está em desenvolvimento. Não há série de releases publicada com suporte nem prazo de resposta garantido. O desenvolvimento atual e a pré-release v0.1.0-alpha.5 são o ponto de partida para investigação; pacotes históricos não recebem correções automaticamente. Não divulgue vulnerabilidade sem correção ou credenciais reais em uma issue pública. Use **Report a vulnerability** no GitHub deste repositório se o relato privado estiver habilitado. Se estiver indisponível, abra uma issue pedindo ao mantenedor um canal privado, sem detalhes da vulnerabilidade. Nunca publique dumps, perfis salvos, payloads DPAPI, tokens ou chaves privadas. diff --git a/THIRD-PARTY-NOTICES.md b/THIRD-PARTY-NOTICES.md index d15d240..c2aa939 100644 --- a/THIRD-PARTY-NOTICES.md +++ b/THIRD-PARTY-NOTICES.md @@ -37,6 +37,8 @@ O PGMS usa os seguintes pacotes, com versões resolvidas registradas nos `packag | Npgsql | 10.0.3 | PostgreSQL License — https://github.com/npgsql/npgsql | | Microsoft.Extensions.Logging.Abstractions | 10.0.0 | MIT — https://github.com/dotnet/runtime | | Microsoft.Extensions.DependencyInjection.Abstractions | 10.0.0 | MIT — https://github.com/dotnet/runtime | +| Anthropic (SDK C#, assistente de IA) | 13.5.0 | Apache-2.0 (MIT nas versões anteriores à 13.0.0; o pacote traz os dois textos) — https://github.com/anthropics/anthropic-sdk-csharp | +| Microsoft.Extensions.AI.Abstractions | 10.5.1 | MIT — https://github.com/dotnet/extensions | Textos de licença estão em `docs/licenses`. Os ícones simples do shell foram desenhados no próprio XAML. Não foram copiados assemblies ou ícones da instalação do SSMS. Nome de referência e nomes de bibliotecas identificam seus respectivos produtos e autores. diff --git a/docs/assets/README.md b/docs/assets/README.md index 581f792..5720587 100644 --- a/docs/assets/README.md +++ b/docs/assets/README.md @@ -7,3 +7,7 @@ The README files show this image with alt text only; the caption above is the provenance record. It is a historical M957 preview captured during M959 and illustrates the interface, not the current release package. A short recording of the alpha package may replace it later. Os READMEs mostram a imagem apenas com texto alternativo; a legenda acima é o registro de origem. É uma prévia histórica M957 capturada na M959 e ilustra a interface, não o pacote da release atual. Uma gravação curta do pacote alpha pode substituí-la depois. + +`pgms-diagram.png`, `pgms-query-designer.png` and `pgms-intellisense.png` were rendered from PGMS (M1053 source) on a disposable loopback cluster with a synthetic shop schema. In `pgms-intellisense.png` the suggestion list, a separate window, was composed over the editor at its real position. + +`pgms-diagram.png`, `pgms-query-designer.png` e `pgms-intellisense.png` foram renderizadas a partir do PGMS (fonte M1053) num cluster descartável em loopback, com um schema sintético de loja. Em `pgms-intellisense.png` a lista de sugestões, que é uma janela separada, foi composta sobre o editor na posição real. diff --git a/docs/assets/pgms-diagram.png b/docs/assets/pgms-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..6662470cbda860e80c5d8f2c722167d412580612 GIT binary patch literal 30429 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 literal 0 HcmV?d00001 diff --git a/docs/assets/pgms-intellisense.png b/docs/assets/pgms-intellisense.png new file mode 100644 index 0000000000000000000000000000000000000000..a3744796c45199f4fbc88488033a072cbb1fca66 GIT binary patch literal 31676 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

S?obJFXGA2aP{S*PGiQMr>`*ZfoM&M9Q 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 literal 0 HcmV?d00001 diff --git a/docs/assets/pgms-query-designer.png b/docs/assets/pgms-query-designer.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbeda396a8343c16885f1516e51bfd47a34e76f GIT binary patch literal 30186 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%0D@ z|3mPs9d3(Zz$E8~RVwdg^RZ_L?;c3yrVP?5a;d^BfEp#i>E_?>o~?@27VON;WQX0m z_wl`0OT7_YeP)_-MqdWxTyG*&j7RRP^c<*zEU=+)AlY;`f299nUa+Xma$MnK8RC7q ze~I)tUKP_Byxw*DJP=(XS3f3UR}20j@?g!{tqLMt9M@jj^hk(w@s*`h+n;9qZGGAQ z?uPT%a35pzbf)qL;3$^r&a0+ zwb$y6WL1ysJ|*dPmS_8?V@(s2TCB-01C(#b_FA|HQ2VCDS6)R)(jgD$)8EMI|FqI= z5``_h0c|4DdI{uR1Q)c%;XjJChOL<%uzcQKzhenHbk9buFm2w|KJN=Xe>76+Q0Pb5 z6vIjW`$jHaY=x#Daa_v9I7GqrpPKMWA~ZeeHb9|MPV7dd=RDBPgp#bhD;~MV1Whq} zMVqaY7e2=tlLjIrK2HxKVIFeGY@K!l*=U zxH27jF|q*yC1E;$jB${p{&~A{D?Cgey3X_}fG5(`r@>fg1}pPyFG+3UkoD{w!%c|& zU2joxth8C?iEb$Wk(X>05nQLFk>n{jmJ1aMV7ie%DK;Rpvxb5ZE?U8u&XClGdu%E} z-5|uE_N9>x6FM)U4$6(ihvx%A)M8ysJn>jrwfWfOsr{)29ZjMUp{I7XC$XN}sl(IP z8Rq>Zhu&Jx0knCHStd6)9Ct~F3o9S7@nYlgz`x#80p1QUkxNgJ`>m!IOGTA&u za01FxYr7V#TOz6wP4A@-p-(vvlt-2m7<9GNNKT%Lm-SH6#smAm@M8LJ`UTgO-c7^H z3Epvs-I#K{!V*#+VP6+dHW=3-G4XZw=p3@~?6d9B*KoC8ajiNYpF?146BeH(xz6Hb$rV{Cf^pv6sJ;k) zLU_8%+wL4Ohm%-i<~&mK)bGTQt{x`lsNN#}0Ram5KYHqnapNmNJbk%;Q!|psUSvVU zD{{CVJnm9jKcAv8PBBo8NNk|}t(o*6R(ekT)Zf1QRXEMIIJaZ^rUU!QZ_w5_d?01t Hsq6m(gM3i@ literal 0 HcmV?d00001 diff --git a/docs/en/README.md b/docs/en/README.md index 6f80475..fa902ab 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -7,7 +7,7 @@ English | [Português (Brasil)](../pt-BR/README.md) 3. [Development](development.md): isolated tests, packaging and contribution workflow. 4. [Architecture](architecture.md): actual projects and important boundaries. 5. [Validation and limits](validation.md): M1008 evidence and historical acceptance. -6. [Licensing](licensing.md): MIT, dependencies, logo and reference materials. +6. [Licensing](licensing.md): Apache-2.0, dependencies, logo and reference materials. 7. [Portable distribution](distribution.md): packaged license, runtime and install scripts. diff --git a/docs/en/distribution.md b/docs/en/distribution.md index ff09696..fb3ec5f 100644 --- a/docs/en/distribution.md +++ b/docs/en/distribution.md @@ -1,4 +1,4 @@ -# PGMS v0.1.0-alpha.4 — portable distribution (M1030) +# PGMS v0.1.0-alpha.5 — portable distribution (M1053) English | Português (Brasil): LEIA-ME.md in the package, or docs/pt-BR/distribution.md in the source repository. diff --git a/docs/en/getting-started.md b/docs/en/getting-started.md index 49ed6e0..057501d 100644 --- a/docs/en/getting-started.md +++ b/docs/en/getting-started.md @@ -2,7 +2,7 @@ English | [Português (Brasil)](../pt-BR/getting-started.md) -[Download v0.1.0-alpha.4](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4): [graphical installer](graphical-installer.md), portable ZIP or PowerShell 7 installer. The graphical installer offers current-user and all-users modes and does not require PowerShell. See [release notes](release-notes.md). +[Download v0.1.0-alpha.5](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5): [graphical installer](graphical-installer.md), portable ZIP or PowerShell 7 installer. The graphical installer offers current-user and all-users modes and does not require PowerShell. See [release notes](release-notes.md). ### Windows SmartScreen warning @@ -15,7 +15,7 @@ Get-FileHash .\PGMS-* -Algorithm SHA256 Compare the hashes with `SHA256SUMS.txt` in the release. Starting with v0.1.0-alpha.2 the assets are built by the [release workflow](../../.github/workflows/release.yml) on GitHub Actions and carry a build provenance attestation, so you can also confirm that the ZIP or installer came from that workflow and this repository (requires the [GitHub CLI](https://cli.github.com/); see [development](development.md)): ```powershell -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` v0.1.0-alpha.1 was built on the maintainer's machine and has checksums only. Code signing through the SignPath Foundation open source program is planned. diff --git a/docs/en/graphical-installer.md b/docs/en/graphical-installer.md index d8d2409..c66f1a0 100644 --- a/docs/en/graphical-installer.md +++ b/docs/en/graphical-installer.md @@ -2,7 +2,7 @@ English | [Português (Brasil)](../pt-BR/graphical-installer.md) -Download `PGMS-0.1.0-alpha.4-Setup-x64.exe` from the [alpha.4 release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4) and check it against `SHA256SUMS.txt` (and, optionally, `gh attestation verify`). Since v0.1.0-alpha.2 the installer is built by the release workflow from the same payload as the portable ZIP of that release; in v0.1.0-alpha.1 it was added later to wrap the existing M1008 payload. The installer does not require PowerShell or a separately installed .NET runtime. +Download `PGMS-0.1.0-alpha.5-Setup-x64.exe` from the [alpha.5 release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5) and check it against `SHA256SUMS.txt` (and, optionally, `gh attestation verify`). Since v0.1.0-alpha.2 the installer is built by the release workflow from the same payload as the portable ZIP of that release; in v0.1.0-alpha.1 it was added later to wrap the existing M1008 payload. The installer does not require PowerShell or a separately installed .NET runtime. ## Installation choices diff --git a/docs/en/licensing.md b/docs/en/licensing.md index 9d76cda..153e8ce 100644 --- a/docs/en/licensing.md +++ b/docs/en/licensing.md @@ -4,7 +4,7 @@ English | [Português (Brasil)](../pt-BR/licensing.md) ## Original work -PGMS's original code and documentation are under the [MIT license](../../LICENSE), chosen by the maintainer. Preserve its copyright and permission notice in copies or substantial portions. The canonical license text is English; this guide explains the project arrangement rather than replacing that text. Third-party software, assets and trademarks do not become MIT-licensed PGMS property through this choice. +PGMS's original code and documentation are under the [Apache License 2.0](../../LICENSE), chosen by the maintainer: free for personal and business use. Anyone redistributing PGMS or a work built on it must keep the copyright notices and the attribution in [NOTICE](../../NOTICE), and state which files they changed. Releases through 0.1.0-alpha.4 remain under MIT. The canonical license text is English; this guide explains the project arrangement rather than replacing that text. Third-party software, assets and trademarks do not become MIT-licensed PGMS property through this choice. ## Dependencies and assets @@ -20,7 +20,7 @@ Versions below follow the current `packages.lock.json` files. Original license t | .NET/WPF self-contained runtime | package-specific | Licenses and notices copied from runtime packs when packaging; M1008 bundles 10.0.14. | | PostgreSQL elephant/Slonik | original artwork | Original license in [PostgreSQL-logo.txt](../licenses/PostgreSQL-logo.txt); [press kit](https://www.postgresql.org/about/press/presskit12/) and [trademark policy](https://www.postgresql.org/about/policies/trademarks/). | -The application artwork includes the PostgreSQL elephant. Copyright permission and trademark conditions are separate. No permission to change/combine marks or imply endorsement is granted by the PGMS MIT license. Keep the original artwork provenance; any public branding redesign must follow the PostgreSQL trademark policy. PGMS is an independent application, without endorsement or affiliation with Microsoft or the PostgreSQL project. +The application artwork includes the PostgreSQL elephant. Copyright permission and trademark conditions are separate. No permission to change/combine marks or imply endorsement is granted by the PGMS license. Keep the original artwork provenance; any public branding redesign must follow the PostgreSQL trademark policy. PGMS is an independent application, without endorsement or affiliation with Microsoft or the PostgreSQL project. ## Installer engine diff --git a/docs/en/public-readiness.md b/docs/en/public-readiness.md index 335b5fb..bd4dfe6 100644 --- a/docs/en/public-readiness.md +++ b/docs/en/public-readiness.md @@ -2,7 +2,7 @@ English | [Português (Brasil)](../pt-BR/public-readiness.md) -This repository is a curated source import with a new Git history. It includes original application code, synthetic test fixtures, selected reproducible build/package scripts, MIT licensing, dependency notices and bilingual public guides. Private development conversations, operational memory/backlog, historical milestone archives, workstation/laboratory setup notes and raw acceptance artifacts are not published here. +This repository is a curated source import with a new Git history. It includes original application code, synthetic test fixtures, selected reproducible build/package scripts, Apache-2.0 licensing, dependency notices and bilingual public guides. Private development conversations, operational memory/backlog, historical milestone archives, workstation/laboratory setup notes and raw acceptance artifacts are not published here. Use GitHub's noreply address for commits when you do not want to publish a personal email. Keep screenshots limited to synthetic data. Do not add saved connection profiles, database dumps, tokens, private keys, encrypted recovery payloads, machine-specific configuration or build/test artifacts. The `.gitignore` is a convenience, not a substitute for reviewing staged content. diff --git a/docs/en/release-notes.md b/docs/en/release-notes.md index ae6bee0..2799ced 100644 --- a/docs/en/release-notes.md +++ b/docs/en/release-notes.md @@ -1,25 +1,32 @@ -# v0.1.0-alpha.4 — Windows x64 +# v0.1.0-alpha.5 — Windows x64 English | [Português (Brasil)](../pt-BR/release-notes.md) -Fourth public pre-release of PGMS. It is an alpha for evaluation with synthetic/disposable data. Build label: M1030. This release rebuilds the Activity Monitor as a document tab with the SSMS panels, adds concurrent detach and sub-partitions to the Partitions dialog and supports PostgreSQL 16. The binaries are built and attested by the same [release workflow](../../.github/workflows/release.yml) as alpha.2 and alpha.3. Original work is MIT; dependency notices and licenses accompany the package. +Fifth public pre-release of PGMS. It is an alpha for evaluation with synthetic/disposable data. Build label: M1053. The binaries are built and attested by the same [release workflow](../../.github/workflows/release.yml) as the previous releases. **License change:** from this release on, original work is under Apache-2.0, with credits in `NOTICE`; releases through alpha.4 remain under MIT. -## What changed since v0.1.0-alpha.3 +## What changed since v0.1.0-alpha.4 -- **Activity Monitor as a document tab with six panels.** **View → Activity Monitor** (`Ctrl+Alt+A`) opens one tab per server and role, reused when opened again. Collapsible panels as in SSMS: **Overview** (charts of active sessions, waiting sessions, database I/O from `pg_stat_io` and transactions per second), **Processes**, **Resource Waits** (sampled wait categories), **Data File I/O** (per database), **Recent Expensive Queries** (the change in `pg_stat_statements` between refreshes) and **Active Expensive Queries** (with **Edit Query Text** and **Show Execution Plan**, an estimated plan that does not execute the query). The Overview context menu sets the interval and pauses, resumes or refreshes the monitor; while paused the header reads "Overview (paused)". See the [user guide](user-guide.md#activity-monitor). -- **Session list closer to SSMS.** Host, **Blocked by PID** and **Head blocker** columns (computed from server-wide `pg_locks`), header tooltips, a row menu (**Details…**, **Cancel Query**, **Terminate Session…**), a **Session Details** dialog with the most recent query, server-side filters and pages by PID (First/Previous/Next). Auto-refresh starts on, every 10 seconds, with intervals from 1 second to 1 hour. -- **Partitions.** **Detach concurrently** runs `DETACH PARTITION … CONCURRENTLY` outside a transaction, without blocking queries, after checking for a DEFAULT partition and for another pending detach; a pending partition is finished with `FINALIZE`. The dialog also creates a partition that is itself partitioned (**Sub-partition by**, keyed by columns of the parent), attaches partitioned tables and detaches partitioned partitions with their sub-tree. -- **PostgreSQL 16.** The supported scope is now PostgreSQL 16 to 18. Query Statistics and Recent Expensive Queries read `pg_stat_statements` 1.10 on PostgreSQL 16; versions older than 1.10 are refused with the `ALTER EXTENSION … UPDATE` they need. -- **Visual fixes.** Inactive document tabs use dark text and the inactive grid selection stays blue, as in SSMS. +- **Database diagrams.** SSMS-style diagrams saved on the server: add tables and related tables, drag a column to create a foreign key, Arrange Tables, zoom, table views, annotations, new tables and column editing inside the diagram. Database changes are shown as a SQL script first. +- **Query Designer.** **Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) with synchronized Diagram, Criteria and SQL panes, joins from foreign keys and Change Type (Update, Delete, Insert Values, Insert Results, Make Table). It writes SQL to the editor and never runs it. +- **IntelliSense.** `Ctrl+Space` and `Ctrl+J` offer what fits the position: tables, views and table functions after `FROM`, searched across all user schemas; whole joins from foreign keys after `JOIN`; columns by alias. Typing ignores accents. +- **Table Designer and View Designer** in document tabs, with a reviewed change script. +- **Graphical execution plans.** Estimated and actual plans drawn with operators and proportional arrows, properties, Find Node, zoom, and opening a saved plan. +- **Faster results.** The thread reading the server no longer waits for the screen, in the grid and in Results to Text. Grids are no longer cut at 10,000 rows or 250,000 cells: larger results are shown in pages of 100,000 rows, configurable in Query Options. +- **Results to Text and to File, Query Options and the Query menu:** per-tab options with defaults in Tools ▸ Options, Parse, Client Statistics and Connection commands. +- **Cancel reaches the server** even while a later statement of the script is running, and no longer risks dropping the connection in the middle of reading. +- **Generate SQL with AI** with Anthropic, OpenAI or a local Ollama, using your own key. Your request and the database structure go to the provider you configure; table data is never read or sent. +- **Configure Server TLS.** A guided setup that installs a certificate and turns on TLS, restoring the previous settings if it fails. Requires a superuser connection to a server running on Windows. +- **Object Explorer and administration.** Standard Reports, Registered Servers, local service Start/Stop/Restart, Edit Top and Select Top rows, Find Missing Foreign Keys, and context menus by node type. +- **About** now shows the author and links to the project. ## Downloads -From [this release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4): +From [this release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5): | File | Purpose | | --- | --- | -| `PGMS-0.1.0-alpha.4-Setup-x64.exe` | Graphical installer (English/pt-BR). Current user without administrator rights, or all users with elevation. No PowerShell or separate .NET runtime required. | -| `PGMS-0.1.0-alpha.4-win-x64.zip` | Portable application with .NET/WPF runtime. Extract the entire folder and run PGMS.exe. Includes the managed PowerShell 7 scripts. | +| `PGMS-0.1.0-alpha.5-Setup-x64.exe` | Graphical installer (English/pt-BR). Current user without administrator rights, or all users with elevation. No PowerShell or separate .NET runtime required. | +| `PGMS-0.1.0-alpha.5-win-x64.zip` | Portable application with .NET/WPF runtime. Extract the entire folder and run PGMS.exe. Includes the managed PowerShell 7 scripts. | | `SHA256SUMS.txt` | SHA256 of every asset in this release. Hashes check correspondence, not authorship. | | `package-manifest.json` | SHA256 manifest of every file inside the ZIP, as checked by `Verify-Package.ps1`. | | `RELEASE-NOTES.md`, `RELEASE-NOTES.pt-BR.md` | These notes. | @@ -30,27 +37,25 @@ The binaries are not code-signed, so Windows SmartScreen may warn on first launc ```powershell Get-FileHash .\PGMS-* -Algorithm SHA256 -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` Compare the hashes with `SHA256SUMS.txt`. The second command needs the [GitHub CLI](https://cli.github.com/) and confirms that the file was produced by this repository's release workflow at the tagged commit; run it for the ZIP as well. Code signing through the SignPath Foundation open source program is planned; no date is promised. ## Scope -SQL editor and independent sessions, Object Explorer, bounded Results/Messages and CSV/JSON export, reviewed PostgreSQL administration (partitions included), identity/privileges, Activity Monitor, query statistics and logical backup/restore. PostgreSQL 16 to 18 and same-major client tools are required for database operations and backup/restore; server/tools are not bundled. Query Statistics and Recent Expensive Queries also require the `pg_stat_statements` extension on the server. SSMS is neither required nor distributed. +SQL editor with IntelliSense and independent sessions, Object Explorer, paged Results and Results to Text/File, CSV/JSON export, database diagrams and designers, graphical plans, reviewed PostgreSQL administration, identity/privileges, Activity Monitor, query statistics and logical backup/restore. PostgreSQL 16 to 18 and same-major client tools are required for database operations and backup/restore; server/tools are not bundled. SSMS is neither required nor distributed. ## Validation -Application behavior: the M1030 source passed the complete PostgreSQL 17.11 regression of this repository (**2,318 integration + 3,429 WPF = 5,747 checks**) on an isolated loopback cluster started with `pg_stat_statements` preloaded; the host PostgreSQL service is not used. On the same source, the focused Activity Monitor suite (`Test-Integration.ps1 -ActivityOnly`) passed 71 integration + 152 WPF checks on PostgreSQL 16.15 and 18.6; the Query Statistics suite passed on 16.15 and 18.6 on the M1029 source, and the Query Statistics code has not changed since. The regression does not run in CI. The Activity Monitor was compared twice with the one in SSMS 22.11 under the same blocking workload; remaining differences are listed in [validation](validation.md). +Application behavior: the M1053 source passed the complete regression of this repository on PostgreSQL 17.11 (**2,834 integration + 4,337 WPF = 7,171 checks**) on an isolated loopback cluster; the host PostgreSQL service is not used. The features added since alpha.4 were not run as a complete regression on PostgreSQL 16 or 18. -Release pipeline: unchanged from v0.1.0-alpha.2. The workflow validates that the tag matches `installer/release.json`, `Directory.Build.props` and `BuildInfo.cs`; publishes with `Publish.ps1 -SelfContained`; runs `Verify-Package.ps1`, `Test-Package.ps1` and `Test-PackageGuides.ps1`; creates the ZIP; builds the installer with the pinned, hash-verified Inno Setup 7.1.1; runs an informational launch smoke on the runner; attests the ZIP and the installer; and opens a draft pre-release that the maintainer reviews before publishing. The draft assets are verified locally before publication, and the result is reported in the release pull request. - -All-users (elevated) installation, a clean-Windows VM installation, a complete regression on PostgreSQL 16 and 18 and physical DPI/keyboard/screen-reader observations of the new screens are not newly certified by this release. +All-users (elevated) installation, a clean-Windows VM installation and physical DPI/keyboard/screen-reader observations of the new screens are not newly certified by this release. New screens were exercised by automated tests, not by hand with mouse and keyboard on this source. ## Known limits -Windows x64 only. Unsigned executable and installer; SmartScreen warns. No MSI, automatic update or production-support guarantee. Full SSMS parity is not claimed. Activity Monitor: Data File I/O is per database, not per file (PostgreSQL has no per-file statistics); Resource Waits is sampled at each refresh, not cumulative; session pages are separate reads and sorting applies within a page; nothing was tested with more than 1,000 sessions. Query Statistics is a snapshot of cumulative server counters, not continuous monitoring; with `pg_stat_statements` 1.10 a time window can count low a statement that was removed and tracked again. The placeholder check assumes `standard_conforming_strings = on` and offers no parameter-value dialog. Results/recovery are bounded; large SQL lines may pause rendering. Cancellation is not proof of rollback. Restore SQL must be trusted and can control transactions, reconnect or execute local psql commands. DPAPI state is tied to the Windows user. The frozen manifest hash in `installer/release.json` describes a locally built payload, not the CI payload; the CI build compares milestone and product version instead. See [validation](validation.md) and [security](../../SECURITY.md). +Windows x64 only. Unsigned executable and installer; SmartScreen warns. No MSI, automatic update or production-support guarantee. Full SSMS parity is not claimed. Results: sorting, copy and export apply to the current page; rows after the first page stay in a temporary file, unencrypted, until the next execution or until the tab closes; Results to Text keeps the 10,000-row and 250,000-cell limits, and Results to File has neither. IntelliSense has no Parameter Info or Quick Info, and does not know CTE columns, temporary tables or `SET search_path` of the session. Query Designer: `UNION` and `WITH` open only in the SQL pane; Update, Delete and Insert Values take one table. Find Missing Foreign Keys is a heuristic: a matching name is a hint, not proof. ## Previous releases -v0.1.0-alpha.3 (2026-11-02, Query Statistics), v0.1.0-alpha.2 (2026-11-01, first CI-built release with attestation) and v0.1.0-alpha.1 (2026-10-31) remain available with their original assets and notes. +v0.1.0-alpha.4 (2026-11-07, Activity Monitor in a tab), v0.1.0-alpha.3 (2026-11-02, Query Statistics), v0.1.0-alpha.2 (2026-11-01, first CI-built release with attestation) and v0.1.0-alpha.1 (2026-10-31) remain available with their original assets and notes, under MIT. diff --git a/docs/en/user-guide.md b/docs/en/user-guide.md index a181ead..f1c38a4 100644 --- a/docs/en/user-guide.md +++ b/docs/en/user-guide.md @@ -16,6 +16,22 @@ Object Explorer loads folders on demand, filters and inspects objects. Supported Identity and sequence operations distinguish configured START from RESTART. A restart can repeat existing values. The **Partitions** dialog creates, attaches and detaches partitions. A new child can itself be partitioned (**Sub-partition by**, keyed by columns of the parent), and a partitioned table can be attached or detached with its sub-tree. **Detach concurrently** runs `DETACH PARTITION … CONCURRENTLY` outside a transaction, without blocking queries; it is refused for a DEFAULT partition or while another detach is pending, and a pending detach is finished with `FINALIZE`. Privilege changes, delegation, CASCADE and COMMIT reconciliation have specific review and concurrency rules. See the [documentation index](../README.md) for supported behavior. +## Database diagrams + +In Object Explorer, right-click **Database Diagrams** under a database and choose **New Database Diagram**. The first time, PGMS asks to create its support objects (schema `pgms`). Add tables with **Add Table** or **Add Related Tables**, drag a column onto another to create a foreign key, and use **Arrange Tables** to lay them out. Saving shows the SQL script of any change to the database for review. + +## Query Designer + +**Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) opens the statement under the cursor, or the selection, in the Diagram, Criteria and SQL panes. **OK** replaces that statement in the editor; nothing is executed. On an empty line it starts empty and inserts at the cursor. `UNION` and `WITH` open only in the SQL pane. + +## IntelliSense + +`Ctrl+Space` or `Ctrl+J` opens the list; typing a dot opens it by itself. `Tab` accepts and `Esc` closes. **Query ▸ IntelliSense Enabled** (`Ctrl+B`, `Ctrl+I`) turns it off for the tab, and **Edit ▸ IntelliSense ▸ Refresh Local Cache** (`Ctrl+Shift+R`) reads the catalog again after schema changes. After `FROM` and similar keywords it searches table names in every user schema; after `JOIN` it offers whole joins from foreign keys. + +## Large results + +A grid result larger than **Query Options ▸ Results ▸ Grid ▸ Rows per result page** (100,000 by default) is shown in pages, with a bar below the grid. Rows after the first page are kept in a temporary file until the next execution or until the tab closes. Sorting, copy and export apply to the current page; **Results to File** writes every row. + ## Activity Monitor **View → Activity Monitor** (`Ctrl+Alt+A`) opens a document tab for the connected server and role (`host:port (role) - Activity Monitor`); opening it again activates the same tab. It has six collapsible panels, following the SSMS layout: diff --git a/docs/en/validation.md b/docs/en/validation.md index f57f9ac..08d56b2 100644 --- a/docs/en/validation.md +++ b/docs/en/validation.md @@ -2,7 +2,7 @@ English | [Português (Brasil)](../pt-BR/validation.md) -Current pre-release: v0.1.0-alpha.4, build label M1030 (adds the Activity Monitor document tab and panels, concurrent detach and sub-partitions, and PostgreSQL 16 support to the M1022 source of alpha.3; built by the release workflow on GitHub Actions with a build provenance attestation). Milestone labels are internal identifiers, not guarantees that a local rebuild has the same binary identity. The initial public source import used M1002. The private operational history and raw acceptance evidence are intentionally not included. +Current pre-release: v0.1.0-alpha.5, build label M1053 (adds database diagrams, the table, view and query designers, IntelliSense, graphical plans, paged results, AI-assisted SQL and the TLS assistant to the M1030 source of alpha.4; built by the release workflow on GitHub Actions with a build provenance attestation). Milestone labels are internal identifiers, not guarantees that a local rebuild has the same binary identity. The initial public source import used M1002. The private operational history and raw acceptance evidence are intentionally not included. The imported implementation previously passed 5,187 automated checks (2,115 PostgreSQL integration and 3,072 WPF), plus package opening, installed profile preservation and three-draft recovery through rollback/restart. Those are historical observations, not newly executed tests for every source revision. Reproduce current behavior with the public build and test scripts; report your actual environment and results. The clean-import checks for the initial public revision are recorded below after execution. @@ -38,6 +38,10 @@ A complete run passed 2,236 integration + 3,315 WPF = 5,551 checks on PostgreSQL The window was compared, during development, with the Query Store of SSMS 22.11 on an identical synthetic workload against SQL Server LocalDB and the disposable PostgreSQL cluster. Both listed the same statements with matching counts. Differences found then: one window instead of seven Query Store reports; server-wide cumulative counters instead of per-database time intervals; no chart, plan, logical reads or header sorting; full records exposed as row names to screen readers. Header sorting, I/O and block metrics, generic plans, the top-N chart, time windows and short row names were added afterward. Remaining differences: one window instead of separate reports, windows computed by subtracting samples rather than stored intervals, and no per-statement CPU time, which PostgreSQL does not record. Physical DPI and screen-reader observations of this window are not newly certified. +## v0.1.0-alpha.5 / M1053 — 2026-11-08 + +A complete run passed 2,834 integration + 4,337 WPF = 7,171 checks on PostgreSQL 17.11, on a disposable loopback cluster with `pg_stat_statements` preloaded. The complete regression was not repeated on PostgreSQL 16 or 18. New screens were exercised by automated tests, not by hand with mouse and keyboard. + ## v0.1.0-alpha.4 / M1030 — 2026-11-04 A complete run passed 2,318 integration + 3,429 WPF = 5,747 checks on PostgreSQL 17.11, on the same disposable loopback cluster with `pg_stat_statements` preloaded; the cluster stopped afterward. In the public checkout, the focused suite `Test-Integration.ps1 -ActivityOnly` passed 71 integration + 152 WPF checks and `-PartitionTablesOnly` passed 113 integration + 101 WPF checks. On the same application source, in the development repository, the Activity Monitor suite passed 71 integration + 152 WPF checks on PostgreSQL 16.15 and on 18.6, with matching-major tools; the Query Statistics suite passed on both versions on the M1029 source, and its code has not changed since. Integration checks cover blocking chains and the head blocker across databases, paging by PID within one snapshot, overview metrics from `pg_stat_io` and `pg_stat_database`, sampled waits that leave out `pg_sleep`, the change in `pg_stat_statements` between refreshes, concurrent detach with its preconditions and `FINALIZE`, and creating, attaching and detaching sub-partitioned tables. WPF checks cover the document tab and its reuse, panels, charts, pause/resume, refresh intervals, row and panel menus, Session Details and minimum-size layout. diff --git a/docs/licenses/Anthropic.txt b/docs/licenses/Anthropic.txt new file mode 100644 index 0000000..64817b2 --- /dev/null +++ b/docs/licenses/Anthropic.txt @@ -0,0 +1,220 @@ +Anthropic C# SDK (package Anthropic 13.5.0) - https://github.com/anthropics/anthropic-sdk-csharp + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Anthropic, PBC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +================================================================================ +LICENSE-MIT (from the same package) +================================================================================ + +This repository changed its license from the MIT License to the Apache License, Version 2.0 (see LICENSE) in version 13.0.0 of the Anthropic package. The MIT License below still applies to every version published under it, and to third-party contributions merged into this repository before the change. + +-------------------------------------------------------------------------------- + +Copyright 2023 Anthropic, PBC. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/licenses/dotnet-extensions.txt b/docs/licenses/dotnet-extensions.txt new file mode 100644 index 0000000..ec66a5e --- /dev/null +++ b/docs/licenses/dotnet-extensions.txt @@ -0,0 +1,25 @@ +Microsoft.Extensions.AI.Abstractions 10.5.1 - https://github.com/dotnet/extensions (MIT, same text as the .NET runtime license) + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/docs/pt-BR/README.md b/docs/pt-BR/README.md index 1830cdd..00baa1e 100644 --- a/docs/pt-BR/README.md +++ b/docs/pt-BR/README.md @@ -7,7 +7,7 @@ 3. [Desenvolvimento](development.md): testes isolados, empacotamento e contribuições. 4. [Arquitetura](architecture.md): projetos existentes e limites importantes. 5. [Validação e limites](validation.md): provas M1008 e aceites históricos. -6. [Licenças](licensing.md): MIT, dependências, logo e materiais da referência. +6. [Licenças](licensing.md): Apache-2.0, dependências, logo e materiais da referência. 7. [Distribuição portátil](distribution.md): licença, runtime e scripts de instalação do pacote. diff --git a/docs/pt-BR/distribution.md b/docs/pt-BR/distribution.md index 336631f..52e0679 100644 --- a/docs/pt-BR/distribution.md +++ b/docs/pt-BR/distribution.md @@ -1,4 +1,4 @@ -# PGMS v0.1.0-alpha.4 — distribuição portátil (M1030) +# PGMS v0.1.0-alpha.5 — distribuição portátil (M1053) [English]: READ-ME.md no pacote, ou docs/en/distribution.md no repositório. Português (Brasil). diff --git a/docs/pt-BR/getting-started.md b/docs/pt-BR/getting-started.md index b645f4a..fe4d9e3 100644 --- a/docs/pt-BR/getting-started.md +++ b/docs/pt-BR/getting-started.md @@ -2,7 +2,7 @@ [English](../en/getting-started.md) | Português (Brasil) -[Baixar v0.1.0-alpha.4](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4): [instalador gráfico](graphical-installer.md), ZIP portátil ou instalador PowerShell 7. O instalador gráfico oferece modos por usuário e para todos, dispensando PowerShell. Veja [notas da versão](release-notes.md). +[Baixar v0.1.0-alpha.5](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5): [instalador gráfico](graphical-installer.md), ZIP portátil ou instalador PowerShell 7. O instalador gráfico oferece modos por usuário e para todos, dispensando PowerShell. Veja [notas da versão](release-notes.md). ### Aviso do SmartScreen do Windows @@ -15,7 +15,7 @@ Get-FileHash .\PGMS-* -Algorithm SHA256 Compare os hashes com o `SHA256SUMS.txt` da release. A partir da v0.1.0-alpha.2 os assets são compilados pelo [workflow de release](../../.github/workflows/release.yml) no GitHub Actions e trazem atestado de proveniência de build, então você também pode confirmar que o ZIP ou o instalador saiu desse workflow e deste repositório (exige o [GitHub CLI](https://cli.github.com/); veja [desenvolvimento](development.md)): ```powershell -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` A v0.1.0-alpha.1 foi compilada na máquina do mantenedor e tem apenas checksums. A assinatura de código pelo programa open source da SignPath Foundation está planejada. diff --git a/docs/pt-BR/graphical-installer.md b/docs/pt-BR/graphical-installer.md index 0343d4a..114f49e 100644 --- a/docs/pt-BR/graphical-installer.md +++ b/docs/pt-BR/graphical-installer.md @@ -2,7 +2,7 @@ [English](../en/graphical-installer.md) | Português (Brasil) -Baixe `PGMS-0.1.0-alpha.4-Setup-x64.exe` na [release alpha.4](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4) e confira contra o `SHA256SUMS.txt` (e, opcionalmente, com `gh attestation verify`). Desde a v0.1.0-alpha.2 o instalador é compilado pelo workflow de release a partir do mesmo payload do ZIP portátil daquela release; na v0.1.0-alpha.1 ele foi adicionado depois, embrulhando o payload M1008 existente. O instalador dispensa PowerShell e runtime .NET instalado separadamente. +Baixe `PGMS-0.1.0-alpha.5-Setup-x64.exe` na [release alpha.5](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5) e confira contra o `SHA256SUMS.txt` (e, opcionalmente, com `gh attestation verify`). Desde a v0.1.0-alpha.2 o instalador é compilado pelo workflow de release a partir do mesmo payload do ZIP portátil daquela release; na v0.1.0-alpha.1 ele foi adicionado depois, embrulhando o payload M1008 existente. O instalador dispensa PowerShell e runtime .NET instalado separadamente. ## Opções de instalação diff --git a/docs/pt-BR/licensing.md b/docs/pt-BR/licensing.md index b5829ef..e15b003 100644 --- a/docs/pt-BR/licensing.md +++ b/docs/pt-BR/licensing.md @@ -4,7 +4,7 @@ ## Trabalho próprio -Código e documentação próprios do PGMS usam a [licença MIT](../../LICENSE), escolhida pelo mantenedor. Preserve o aviso de copyright e permissão nas cópias ou partes substanciais. O texto canônico está em inglês; este guia explica a organização do projeto, sem substituir o texto. Software, recursos e marcas de terceiros não se tornam propriedade MIT do PGMS por essa escolha. +Código e documentação próprios do PGMS usam a [Apache License 2.0](../../LICENSE), escolhida pelo mantenedor: uso livre pessoal e em empresas. Quem redistribuir o PGMS ou uma obra baseada nele precisa manter os avisos de copyright e a atribuição do [NOTICE](../../NOTICE), e indicar os arquivos que alterou. As versões até 0.1.0-alpha.4 continuam sob MIT. O texto canônico está em inglês; este guia explica a organização do projeto, sem substituir o texto. Software, recursos e marcas de terceiros não se tornam propriedade MIT do PGMS por essa escolha. ## Dependências e recursos @@ -20,7 +20,7 @@ As versões seguem os `packages.lock.json` atuais. Textos originais estão em [d | Runtime .NET/WPF self-contained | depende do pacote | Licenças/avisos copiados dos runtime packs ao empacotar; M1008 inclui 10.0.14. | | Elefante PostgreSQL/Slonik | arte original | Licença em [PostgreSQL-logo.txt](../licenses/PostgreSQL-logo.txt); [press kit](https://www.postgresql.org/about/press/presskit12/) e [política de marcas](https://www.postgresql.org/about/policies/trademarks/). | -A arte do aplicativo inclui o elefante PostgreSQL. Permissão autoral e condições de marca são distintas. A licença MIT do PGMS não concede permissão para alterar/combinar marcas ou sugerir endosso. Preserve a origem da arte; qualquer redesign público da marca deve seguir a política PostgreSQL. PGMS é independente, sem endosso ou afiliação com Microsoft ou projeto PostgreSQL. +A arte do aplicativo inclui o elefante PostgreSQL. Permissão autoral e condições de marca são distintas. A licença do PGMS não concede permissão para alterar/combinar marcas ou sugerir endosso. Preserve a origem da arte; qualquer redesign público da marca deve seguir a política PostgreSQL. PGMS é independente, sem endosso ou afiliação com Microsoft ou projeto PostgreSQL. ## Mecanismo do instalador diff --git a/docs/pt-BR/public-readiness.md b/docs/pt-BR/public-readiness.md index aebdfb4..9109ee0 100644 --- a/docs/pt-BR/public-readiness.md +++ b/docs/pt-BR/public-readiness.md @@ -2,7 +2,7 @@ [English](../en/public-readiness.md) | Português (Brasil) -Este repositório é uma importação selecionada de fonte com histórico Git novo. Inclui código próprio, testes sintéticos, scripts selecionados de build/pacote reproduzíveis, licença MIT, avisos de dependências e guias públicos bilíngues. Conversas de desenvolvimento, memória/backlog operacional, arquivos de marcos, anotações de máquinas/laboratório e artefatos brutos de aceitação privados não são publicados aqui. +Este repositório é uma importação selecionada de fonte com histórico Git novo. Inclui código próprio, testes sintéticos, scripts selecionados de build/pacote reproduzíveis, licença Apache-2.0, avisos de dependências e guias públicos bilíngues. Conversas de desenvolvimento, memória/backlog operacional, arquivos de marcos, anotações de máquinas/laboratório e artefatos brutos de aceitação privados não são publicados aqui. Use o endereço noreply do GitHub nos commits quando não quiser publicar e-mail pessoal. Limite capturas a dados sintéticos. Não adicione perfis salvos, dumps, tokens, chaves privadas, payloads de recuperação criptografados, configuração específica de máquina ou artefatos de build/teste. `.gitignore` é conveniência, não substitui revisar o conteúdo preparado para commit. diff --git a/docs/pt-BR/release-notes.md b/docs/pt-BR/release-notes.md index 72e24df..a235807 100644 --- a/docs/pt-BR/release-notes.md +++ b/docs/pt-BR/release-notes.md @@ -1,56 +1,61 @@ -# v0.1.0-alpha.4 — Windows x64 +# v0.1.0-alpha.5 — Windows x64 [English](../en/release-notes.md) | Português (Brasil) -Quarta pré-release pública do PGMS. É uma versão alpha para avaliação com dados sintéticos/descartáveis. Rótulo de build: M1030. Esta release refaz o Activity Monitor como aba de documento com os painéis do SSMS, acrescenta detach concorrente e subpartições ao diálogo Partitions e passa a suportar o PostgreSQL 16. Os binários são compilados e atestados pelo mesmo [workflow de release](../../.github/workflows/release.yml) da alpha.2 e da alpha.3. Trabalho próprio MIT; avisos e licenças das dependências acompanham o pacote. +Quinta pré-release pública do PGMS. É uma alpha para avaliação com dados sintéticos ou descartáveis. Rótulo de build: M1053. Os binários são gerados e atestados pelo mesmo [workflow de release](../../.github/workflows/release.yml) das versões anteriores. **Mudança de licença:** a partir desta versão, o trabalho próprio está sob Apache-2.0, com créditos no `NOTICE`; as versões até a alpha.4 continuam sob MIT. -## O que mudou desde a v0.1.0-alpha.3 +## O que mudou desde a v0.1.0-alpha.4 -- **Activity Monitor em aba de documento, com seis painéis.** **View → Activity Monitor** (`Ctrl+Alt+A`) abre uma aba por servidor e role, reaproveitada ao abrir de novo. Painéis recolhíveis como no SSMS: **Overview** (gráficos de sessões ativas, sessões em espera, I/O do banco via `pg_stat_io` e transações por segundo), **Processes**, **Resource Waits** (categorias de espera amostradas), **Data File I/O** (por database), **Recent Expensive Queries** (variação do `pg_stat_statements` entre atualizações) e **Active Expensive Queries** (com **Edit Query Text** e **Show Execution Plan**, plano estimado que não executa a consulta). O menu de contexto do Overview define o intervalo e pausa, retoma ou atualiza o monitor; em pausa, o título mostra "Overview (paused)". Veja o [guia de uso](user-guide.md#activity-monitor). -- **Lista de sessões mais próxima do SSMS.** Colunas Host, **Blocked by PID** e **Head blocker** (calculado sobre `pg_locks` do servidor inteiro), dicas nos cabeçalhos, menu da linha (**Details…**, **Cancel Query**, **Terminate Session…**), diálogo **Session Details** com a consulta mais recente, filtros no servidor e páginas por PID (First/Previous/Next). A atualização automática começa ligada a cada 10 segundos, com intervalos de 1 segundo a 1 hora. -- **Partições.** **Detach concurrently** executa `DETACH PARTITION … CONCURRENTLY` fora de transação, sem bloquear consultas, com checagem prévia de partição DEFAULT e de outro detach pendente; uma partição pendente é concluída com `FINALIZE`. O diálogo também cria uma partição já particionada (**Sub-partition by**, com chave de colunas do pai), anexa tabelas particionadas e desanexa partições particionadas preservando a subárvore. -- **PostgreSQL 16.** O escopo suportado passa a ser PostgreSQL 16 a 18. O Query Statistics e o Recent Expensive Queries leem o `pg_stat_statements` 1.10 do PostgreSQL 16; versões anteriores à 1.10 são recusadas com a indicação do `ALTER EXTENSION … UPDATE` necessário. -- **Ajustes visuais.** Abas de documento inativas usam texto escuro e a seleção inativa nas grades fica azul, como no SSMS. +- **Diagramas de banco.** Diagramas como os do SSMS, salvos no servidor: adicionar tabelas e tabelas relacionadas, arrastar uma coluna para criar chave estrangeira, Arrange Tables, zoom, modos de exibição, anotações, tabelas novas e edição de colunas dentro do diagrama. Alterações no banco aparecem antes como script SQL. +- **Query Designer.** **Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) com painéis Diagram, Criteria e SQL sincronizados, junções pelas chaves estrangeiras e Change Type (Update, Delete, Insert Values, Insert Results, Make Table). Ele escreve SQL no editor e nunca executa. +- **IntelliSense.** `Ctrl+Space` e `Ctrl+J` oferecem o que cabe na posição: tabelas, views e funções de tabela depois de `FROM`, buscadas em todos os schemas de usuário; junções inteiras pelas chaves estrangeiras depois de `JOIN`; colunas por alias. A busca ignora acentos. +- **Table Designer e View Designer** em abas de documento, com script de alteração para revisão. +- **Planos de execução gráficos.** Planos estimados e reais desenhados com operadores e setas proporcionais, propriedades, Find Node, zoom e abertura de plano salvo. +- **Resultados mais rápidos.** A thread que lê o servidor não espera mais a tela, na grade e em Results to Text. A grade não corta mais em 10.000 linhas ou 250.000 células: resultados maiores aparecem em páginas de 100.000 linhas, configurável em Query Options. +- **Results to Text e to File, Query Options e menu Query:** opções por aba com padrões em Tools ▸ Options, Parse, Client Statistics e comandos de Connection. +- **Cancelar chega ao servidor** mesmo com uma instrução seguinte do script em execução, e não arrisca mais derrubar a conexão no meio da leitura. +- **Gerar SQL com IA** com Anthropic, OpenAI ou um Ollama local, usando a sua própria chave. O pedido e a estrutura do banco vão para o provedor que você configurar; dados das tabelas nunca são lidos nem enviados. +- **Configure Server TLS.** Assistente que instala um certificado e liga o TLS, restaurando a configuração anterior se algo falhar. Exige conexão de superusuário a um servidor em Windows. +- **Object Explorer e administração.** Standard Reports, Registered Servers, Start/Stop/Restart do serviço local, Edit Top e Select Top, Find Missing Foreign Keys e menus de contexto por tipo de nó. +- **About** agora mostra o autor e os links do projeto. ## Downloads -Nesta [release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.4): +Em [esta release](https://github.com/leoars/PostgresManagementStudio/releases/tag/v0.1.0-alpha.5): | Arquivo | Finalidade | | --- | --- | -| `PGMS-0.1.0-alpha.4-Setup-x64.exe` | Instalador gráfico (inglês/pt-BR). Por usuário sem direitos de administrador, ou para todos com elevação. Não exige PowerShell nem runtime .NET separado. | -| `PGMS-0.1.0-alpha.4-win-x64.zip` | Aplicativo portátil com runtime .NET/WPF. Extraia toda a pasta e execute PGMS.exe. Inclui os scripts gerenciados PowerShell 7. | -| `SHA256SUMS.txt` | SHA256 de todos os assets desta release. Hash confere correspondência, não autoria. | +| `PGMS-0.1.0-alpha.5-Setup-x64.exe` | Instalador gráfico (inglês/pt-BR). Usuário atual sem administrador, ou todos os usuários com elevação. Não exige PowerShell nem runtime .NET separado. | +| `PGMS-0.1.0-alpha.5-win-x64.zip` | Aplicativo portátil com runtime .NET/WPF. Extraia a pasta inteira e execute PGMS.exe. Inclui os scripts PowerShell 7 gerenciados. | +| `SHA256SUMS.txt` | SHA256 de cada arquivo desta release. Hashes conferem correspondência, não autoria. | | `package-manifest.json` | Manifesto SHA256 de cada arquivo dentro do ZIP, conferido por `Verify-Package.ps1`. | | `RELEASE-NOTES.md`, `RELEASE-NOTES.pt-BR.md` | Estas notas. | -## Verifique o que baixou +## Confira o que você baixou -Os binários não são assinados digitalmente, então o SmartScreen do Windows pode avisar na primeira execução. Antes de escolher **Executar assim mesmo**, confirme o checksum e a proveniência: +Os binários não têm assinatura de código, então o Windows SmartScreen pode avisar na primeira execução. Antes de escolher **Executar assim mesmo**, confira o checksum e a origem: ```powershell Get-FileHash .\PGMS-* -Algorithm SHA256 -gh attestation verify .\PGMS-0.1.0-alpha.4-Setup-x64.exe --repo leoars/PostgresManagementStudio +gh attestation verify .\PGMS-0.1.0-alpha.5-Setup-x64.exe --repo leoars/PostgresManagementStudio ``` -Compare os hashes com o `SHA256SUMS.txt`. O segundo comando exige o [GitHub CLI](https://cli.github.com/) e confirma que o arquivo foi produzido pelo workflow de release deste repositório no commit da tag; execute-o também para o ZIP. A assinatura de código pelo programa open source da SignPath Foundation está planejada; nenhuma data é prometida. +Compare os hashes com `SHA256SUMS.txt`. O segundo comando exige o [GitHub CLI](https://cli.github.com/) e confirma que o arquivo foi gerado pelo workflow de release deste repositório no commit da tag; rode também para o ZIP. A assinatura de código pelo programa open source da SignPath Foundation está planejada, sem data prometida. ## Escopo -Editor SQL e sessões independentes, Object Explorer, Results/Messages com limites e exportação CSV/JSON, administração PostgreSQL revisada (inclusive partições), identity/privilégios, Activity Monitor, estatísticas de consultas e backup/restore lógico. PostgreSQL 16 a 18 e ferramentas da mesma versão principal são necessários para operações com banco e backup/restore; não são incluídos. Query Statistics e Recent Expensive Queries também exigem a extensão `pg_stat_statements` no servidor. SSMS não é exigido nem distribuído. +Editor SQL com IntelliSense e sessões independentes, Object Explorer, Results em páginas e Results to Text/File, exportação CSV/JSON, diagramas de banco e designers, planos gráficos, administração PostgreSQL revisada, identidade/privilégios, Activity Monitor, estatísticas de consultas e backup/restore lógico. PostgreSQL 16 a 18 e ferramentas cliente da mesma versão principal são necessários para operações no banco e backup/restore; servidor e ferramentas não acompanham o pacote. O SSMS não é exigido nem distribuído. ## Validação -Comportamento do aplicativo: a fonte M1030 passou na regressão completa PostgreSQL 17.11 deste repositório (**2.318 integração + 3.429 WPF = 5.747 checks**) em cluster isolado em loopback iniciado com `pg_stat_statements` pré-carregado; o serviço PostgreSQL do host não é usado. Na mesma fonte, a suíte focada do Activity Monitor (`Test-Integration.ps1 -ActivityOnly`) passou em 71 checks de integração + 152 WPF no PostgreSQL 16.15 e no 18.6; a do Query Statistics passou no 16.15 e no 18.6 sobre a fonte M1029, e o código do Query Statistics não mudou depois dela. A regressão não roda no CI. O Activity Monitor foi comparado duas vezes com o do SSMS 22.11 sob a mesma carga de bloqueio; as diferenças restantes estão em [validação](validation.md). +Comportamento do aplicativo: a fonte M1053 passou na regressão completa deste repositório no PostgreSQL 17.11 (**2.834 de integração + 4.337 WPF = 7.171 verificações**), num cluster isolado em loopback; o serviço PostgreSQL do computador não é usado. Os recursos acrescentados desde a alpha.4 não passaram por regressão completa no PostgreSQL 16 ou 18. -Pipeline de release: igual ao da v0.1.0-alpha.2. O workflow valida que a tag corresponde a `installer/release.json`, `Directory.Build.props` e `BuildInfo.cs`; publica com `Publish.ps1 -SelfContained`; roda `Verify-Package.ps1`, `Test-Package.ps1` e `Test-PackageGuides.ps1`; cria o ZIP; compila o instalador com o Inno Setup 7.1.1 fixado e conferido por hash; executa um smoke informacional de abertura no runner; atesta o ZIP e o instalador; e abre uma pré-release em rascunho que o mantenedor revisa antes de publicar. Os assets do rascunho são verificados localmente antes da publicação, e o resultado é relatado no pull request da release. - -Instalação para todos os usuários (elevada), instalação em VM Windows limpa, regressão completa no PostgreSQL 16 e 18 e observações físicas de DPI/teclado/leitor de tela das novas telas não recebem nova certificação nesta release. +Instalação para todos os usuários (com elevação), instalação em VM Windows limpa e observações físicas de DPI, teclado e leitor de tela nas telas novas não são certificadas de novo por esta release. As telas novas foram exercitadas por testes automáticos, não à mão com mouse e teclado nesta fonte. ## Limites conhecidos -Somente Windows x64. Executável e instalador sem assinatura; o SmartScreen avisa. Sem MSI, atualização automática ou garantia de suporte em produção. Não se declara paridade integral SSMS. Activity Monitor: Data File I/O é por database, não por arquivo (o PostgreSQL não tem estatísticas por arquivo); Resource Waits é amostrado a cada atualização, não acumulado; as páginas de sessões são leituras separadas e a ordenação vale dentro da página; nenhum teste com mais de 1.000 sessões. Query Statistics é um snapshot de contadores acumulados do servidor, não monitoramento contínuo; no `pg_stat_statements` 1.10 uma janela de tempo pode contar a menos um statement removido e rastreado de novo. A detecção de placeholders supõe `standard_conforming_strings = on` e não oferece diálogo de valores de parâmetros. Resultados/recuperação têm limites; linhas SQL grandes podem pausar renderização. Cancelar não comprova rollback. SQL de restore exige confiança e pode controlar transações, reconectar ou executar comandos locais psql. Estado DPAPI depende do usuário Windows. O hash de manifesto congelado em `installer/release.json` descreve um payload compilado localmente, não o do CI; o build no CI compara marco e versão do produto. Veja [validação](validation.md) e [segurança](../../SECURITY.pt-BR.md). +Somente Windows x64. Executável e instalador sem assinatura; o SmartScreen avisa. Sem MSI, atualização automática ou garantia de suporte em produção. Não se declara paridade completa com o SSMS. Resultados: ordenação, cópia e exportação valem para a página atual; as linhas depois da primeira página ficam num arquivo temporário, sem criptografia, até a próxima execução ou até a aba fechar; Results to Text mantém os limites de 10.000 linhas e 250.000 células, e Results to File não tem nenhum dos dois. O IntelliSense não tem Parameter Info nem Quick Info, e não conhece colunas de CTE, tabelas temporárias nem o `SET search_path` da sessão. Query Designer: `UNION` e `WITH` abrem apenas no painel SQL; Update, Delete e Insert Values aceitam uma tabela. Find Missing Foreign Keys é heurística: um nome igual é indício, não prova. -## Releases anteriores +## Versões anteriores -A v0.1.0-alpha.3 (02/11/2026, Query Statistics), a v0.1.0-alpha.2 (01/11/2026, primeira compilada pelo CI com atestado) e a v0.1.0-alpha.1 (31/10/2026) continuam disponíveis com seus assets e notas originais. +v0.1.0-alpha.4 (07/11/2026, Activity Monitor em aba), v0.1.0-alpha.3 (02/11/2026, Query Statistics), v0.1.0-alpha.2 (01/11/2026, primeira release gerada por CI com atestado) e v0.1.0-alpha.1 (31/10/2026) continuam disponíveis com seus arquivos e notas originais, sob MIT. diff --git a/docs/pt-BR/user-guide.md b/docs/pt-BR/user-guide.md index cbe7872..6f3bad9 100644 --- a/docs/pt-BR/user-guide.md +++ b/docs/pt-BR/user-guide.md @@ -16,6 +16,22 @@ Object Explorer carrega pastas sob demanda, filtra e inspeciona objetos. Operaç Identity e sequences distinguem START configurado de RESTART. Reiniciar pode repetir valores existentes. O diálogo **Partitions** cria, anexa e desanexa partições. Uma filha nova pode ser ela própria particionada (**Sub-partition by**, com chave de colunas do pai), e uma tabela particionada pode ser anexada ou desanexada com sua subárvore. **Detach concurrently** executa `DETACH PARTITION … CONCURRENTLY` fora de transação, sem bloquear consultas; é recusado para partição DEFAULT ou quando já há outro detach pendente, e um detach pendente é concluído com `FINALIZE`. Privilégios, delegação, CASCADE e reconciliação de COMMIT têm regras próprias de revisão e concorrência. Veja o [índice da documentação](../README.md) para os comportamentos suportados. +## Diagramas de banco de dados + +No Object Explorer, clique com o botão direito em **Database Diagrams**, dentro de um banco, e escolha **New Database Diagram**. Na primeira vez, o PGMS pede para criar seus objetos de suporte (schema `pgms`). Adicione tabelas com **Add Table** ou **Add Related Tables**, arraste uma coluna sobre outra para criar uma chave estrangeira e use **Arrange Tables** para organizar. Ao salvar, o PGMS mostra o script SQL de qualquer alteração no banco para revisão. + +## Query Designer + +**Query ▸ Design Query in Editor** (`Ctrl+Shift+Q`) abre a instrução sob o cursor, ou a seleção, nos painéis Diagram, Criteria e SQL. **OK** substitui essa instrução no editor; nada é executado. Numa linha vazia, abre vazio e insere no cursor. `UNION` e `WITH` abrem apenas no painel SQL. + +## IntelliSense + +`Ctrl+Space` ou `Ctrl+J` abrem a lista; digitar um ponto abre sozinho. `Tab` aceita e `Esc` fecha. **Query ▸ IntelliSense Enabled** (`Ctrl+B`, `Ctrl+I`) desliga na aba, e **Edit ▸ IntelliSense ▸ Refresh Local Cache** (`Ctrl+Shift+R`) relê o catálogo depois de mudanças de schema. Depois de `FROM` e palavras parecidas, busca o nome da tabela em todos os schemas de usuário; depois de `JOIN`, oferece junções inteiras a partir das chaves estrangeiras. + +## Resultados grandes + +Um resultado na grade maior que **Query Options ▸ Results ▸ Grid ▸ Rows per result page** (100.000 por padrão) aparece em páginas, com uma barra abaixo da grade. As linhas depois da primeira página ficam num arquivo temporário até a próxima execução ou até a aba fechar. Ordenação, cópia e exportação valem para a página atual; **Results to File** grava todas as linhas. + ## Activity Monitor **View → Activity Monitor** (`Ctrl+Alt+A`) abre uma aba de documento para o servidor e a role conectados (`host:porta (role) - Activity Monitor`); abrir de novo ativa a mesma aba. Tem seis painéis recolhíveis, seguindo o layout do SSMS: diff --git a/docs/pt-BR/validation.md b/docs/pt-BR/validation.md index f465e19..74dfcfa 100644 --- a/docs/pt-BR/validation.md +++ b/docs/pt-BR/validation.md @@ -2,7 +2,7 @@ [English](../en/validation.md) | Português (Brasil) -Pré-release atual: v0.1.0-alpha.4, rótulo M1030 (acrescenta a aba e os painéis do Activity Monitor, detach concorrente e subpartições e suporte ao PostgreSQL 16 à fonte M1022 da alpha.3; compilada pelo workflow de release no GitHub Actions com atestado de proveniência de build). Marcos são identificadores internos, não garantia de identidade binária de uma recompilação local. A importação pública inicial usou M1002. Histórico operacional e provas brutas privados não são incluídos intencionalmente. +Pré-release atual: v0.1.0-alpha.5, rótulo M1053 (acrescenta diagramas de banco, os designers de tabela, view e consulta, IntelliSense, planos gráficos, resultados em páginas, SQL assistido por IA e o assistente de TLS à fonte M1030 da alpha.4; compilada pelo workflow de release no GitHub Actions com atestado de proveniência de build). Marcos são identificadores internos, não garantia de identidade binária de uma recompilação local. A importação pública inicial usou M1002. Histórico operacional e provas brutas privados não são incluídos intencionalmente. A implementação importada passou anteriormente em 5.187 checks automatizados (2.115 integração PostgreSQL e 3.072 WPF), além de abertura de pacote, preservação de perfil instalado e recuperação de três rascunhos entre rollback/reinício. São observações históricas, não testes novos a cada revisão. Reproduza o comportamento atual pelos scripts públicos e informe ambiente/resultados reais. As verificações da revisão pública inicial são registradas abaixo após execução. @@ -38,6 +38,10 @@ Uma execução completa passou em 2.236 checks de integração + 3.315 WPF = 5.5 Durante o desenvolvimento, a janela foi comparada com o Query Store do SSMS 22.11 sob carga sintética idêntica, contra SQL Server LocalDB e o cluster PostgreSQL descartável. Os dois listaram os mesmos statements com contagens iguais. Diferenças encontradas na época: uma janela em vez de sete relatórios do Query Store; contadores acumulados do servidor em vez de intervalos de tempo por banco; sem gráfico, plano, leituras lógicas ou ordenação pelo cabeçalho; registros inteiros expostos como nome das linhas a leitores de tela. Ordenação pelo cabeçalho, métricas de I/O e blocos, planos genéricos, gráfico top-N, janelas de tempo e nomes curtos de linha foram acrescentados depois. Diferenças que permanecem: uma janela em vez de relatórios separados, janelas calculadas subtraindo amostras em vez de intervalos armazenados, e sem tempo de CPU por statement, que o PostgreSQL não registra. Observações físicas de DPI e leitor de tela desta janela não recebem nova certificação. +## v0.1.0-alpha.5 / M1053 — 08/11/2026 + +Uma execução completa passou com 2.834 de integração + 4.337 WPF = 7.171 verificações no PostgreSQL 17.11, num cluster descartável em loopback com `pg_stat_statements` pré-carregado. A regressão completa não foi repetida no PostgreSQL 16 ou 18. As telas novas foram exercitadas por testes automáticos, não à mão com mouse e teclado. + ## v0.1.0-alpha.4 / M1030 — 04/11/2026 Uma execução completa passou em 2.318 checks de integração + 3.429 WPF = 5.747 no PostgreSQL 17.11, no mesmo cluster descartável em loopback com `pg_stat_statements` pré-carregado; o cluster foi encerrado ao final. No checkout público, a suíte focada `Test-Integration.ps1 -ActivityOnly` passou em 71 checks de integração + 152 WPF e `-PartitionTablesOnly` em 113 de integração + 101 WPF. Sobre a mesma fonte do aplicativo, no repositório de desenvolvimento, a suíte do Activity Monitor passou em 71 checks de integração + 152 WPF no PostgreSQL 16.15 e no 18.6, com ferramentas da mesma versão principal; a do Query Statistics passou nas duas versões sobre a fonte M1029, e o código dela não mudou depois. A integração cobre cadeias de bloqueio e o head blocker entre databases, páginas por PID dentro de um mesmo snapshot, métricas do Overview a partir de `pg_stat_io` e `pg_stat_database`, esperas amostradas sem `pg_sleep`, a variação do `pg_stat_statements` entre atualizações, detach concorrente com suas pré-condições e `FINALIZE`, e criação, attach e detach de tabelas subparticionadas. O WPF cobre a aba de documento e seu reaproveitamento, painéis, gráficos, pausa/retomada, intervalos de atualização, menus da linha e do painel, Session Details e layout no tamanho mínimo. diff --git a/installer/release.json b/installer/release.json index d80102b..79bf22b 100644 --- a/installer/release.json +++ b/installer/release.json @@ -1,6 +1,6 @@ { - "Version": "0.1.0-alpha.4", - "NumericVersion": "0.1.0.4", - "Milestone": "M1030", - "ManifestSha256": "0BCAB13B5309F9113388BE8AED412E928A52BA4D8C53D902DBD435CACBFCBAEC" + "Version": "0.1.0-alpha.5", + "NumericVersion": "0.1.0.5", + "Milestone": "M1053", + "ManifestSha256": "2FDB9AFCA7DD6D093EA1DB16879CE374E20BF5439FBF58A9467B45662825FC0A" } diff --git a/scripts/Publish.ps1 b/scripts/Publish.ps1 index 091acbf..dbf9e31 100644 --- a/scripts/Publish.ps1 +++ b/scripts/Publish.ps1 @@ -28,7 +28,7 @@ try { $publishArgs += @('-p:DebugType=None', '-p:DebugSymbols=false', '-p:IncludeSourceRevisionInInformationalVersion=false', "-p:PathMap=$projectRoot=/_/PGMS") dotnet publish src/PGMS.Desktop/PGMS.Desktop.csproj -c Release --no-restore -o $stagingPath @publishArgs if ($LASTEXITCODE -ne 0) { throw "Publish failed; staging retained at $stagingPath" } - Copy-Item -LiteralPath 'LICENSE', 'THIRD-PARTY-NOTICES.md' -Destination $stagingPath + Copy-Item -LiteralPath 'LICENSE', 'NOTICE', 'THIRD-PARTY-NOTICES.md' -Destination $stagingPath Copy-Item -LiteralPath 'docs/pt-BR/distribution.md' -Destination (Join-Path $stagingPath 'LEIA-ME.md') Copy-Item -LiteralPath 'docs/en/distribution.md' -Destination (Join-Path $stagingPath 'READ-ME.md') New-Item -ItemType Directory -Path (Join-Path $stagingPath 'licenses') | Out-Null diff --git a/scripts/Test-Integration.ps1 b/scripts/Test-Integration.ps1 index ef3aed5..c551166 100644 --- a/scripts/Test-Integration.ps1 +++ b/scripts/Test-Integration.ps1 @@ -1,6 +1,6 @@ -param([switch]$SessionsOnly, [switch]$PlansOnly, [switch]$ExportOnly, [switch]$ActivityOnly, [switch]$QueryStatisticsOnly, [switch]$GlobalBackupOnly, [switch]$ColumnTypesOnly, [switch]$IndexMaintenanceOnly, [switch]$IndexExpressionsOnly, [switch]$PartitionTablesOnly, [switch]$DesktopOnly, [switch]$CascadeJournalOnly, [switch]$CascadeRoutinesOnly, [switch]$CascadeRollbackOnly, [switch]$RevokePreviewOnly, [switch]$GrantorConcurrencyOnly, [switch]$ExplicitGrantorOnly, [switch]$GrantorCatalogOnly, [switch]$DefaultProcessOnly, [switch]$DefaultDelegationOnly, [switch]$DefaultSchemasOnly, [switch]$DefaultTypesOnly, [switch]$DefaultRoutinesOnly, [switch]$DefaultSequencesOnly, [switch]$DefaultTablesOnly, [switch]$DefaultCancellationOnly, [switch]$DefaultUiOnly, [switch]$DefaultJournalOnly, [switch]$DefaultPrivilegesOnly, [switch]$RoutineBoundariesOnly, [switch]$RoutineProcessOnly, [switch]$RoutineConcurrencyOnly, [switch]$RoutinePrivilegesOnly, [string]$PostgresBin = 'C:\Program Files\PostgreSQL\17\bin', [switch]$BackupFormatsOnly, [switch]$IdentityColumnsOnly, [switch]$RestoreOwnershipOnly, [switch]$UnicodeBackupOnly, [switch]$PrivilegeJournalOnly, [switch]$MaintainPrivilegeOnly, [switch]$PrivilegeCommitOnly, [switch]$UnicodePasswordOnly, [switch]$MembershipOptionsOnly, [switch]$PrivilegeIdentityOnly, [switch]$ColumnPrivilegesOnly, [switch]$PrivilegeCancellationOnly, [switch]$EffectivePrivilegesOnly, [switch]$PrivilegeCommandsOnly, [switch]$SequencePrivilegesOnly, [switch]$CopyOnly, [switch]$AdvancedIndexesOnly, [switch]$SequencesOnly, [switch]$SequenceStateOnly, [switch]$SequenceOwnerOnly, [switch]$AccessibilityOnly, [switch]$ConnectionOnly, [switch]$StreamingOnly, [switch]$ExplorerOnly, [switch]$PropertiesOnly, [switch]$AcceptanceOnly, [ValidateRange(1024,65535)][int]$TestPort = 55439) +param([switch]$ResultsTextOnly, [switch]$TableDesignOnly, [switch]$DiagramsOnly, [switch]$ServerTlsOnly, [switch]$SchemaContextOnly, [switch]$ReportsOnly, [switch]$SessionsOnly, [switch]$PlansOnly, [switch]$ExportOnly, [switch]$ActivityOnly, [switch]$QueryStatisticsOnly, [switch]$GlobalBackupOnly, [switch]$ColumnTypesOnly, [switch]$IndexMaintenanceOnly, [switch]$IndexExpressionsOnly, [switch]$PartitionTablesOnly, [switch]$DesktopOnly, [switch]$CascadeJournalOnly, [switch]$CascadeRoutinesOnly, [switch]$CascadeRollbackOnly, [switch]$RevokePreviewOnly, [switch]$GrantorConcurrencyOnly, [switch]$ExplicitGrantorOnly, [switch]$GrantorCatalogOnly, [switch]$DefaultProcessOnly, [switch]$DefaultDelegationOnly, [switch]$DefaultSchemasOnly, [switch]$DefaultTypesOnly, [switch]$DefaultRoutinesOnly, [switch]$DefaultSequencesOnly, [switch]$DefaultTablesOnly, [switch]$DefaultCancellationOnly, [switch]$DefaultUiOnly, [switch]$DefaultJournalOnly, [switch]$DefaultPrivilegesOnly, [switch]$RoutineBoundariesOnly, [switch]$RoutineProcessOnly, [switch]$RoutineConcurrencyOnly, [switch]$RoutinePrivilegesOnly, [string]$PostgresBin = 'C:\Program Files\PostgreSQL\17\bin', [switch]$BackupFormatsOnly, [switch]$IdentityColumnsOnly, [switch]$RestoreOwnershipOnly, [switch]$UnicodeBackupOnly, [switch]$PrivilegeJournalOnly, [switch]$MaintainPrivilegeOnly, [switch]$PrivilegeCommitOnly, [switch]$UnicodePasswordOnly, [switch]$MembershipOptionsOnly, [switch]$PrivilegeIdentityOnly, [switch]$ColumnPrivilegesOnly, [switch]$PrivilegeCancellationOnly, [switch]$EffectivePrivilegesOnly, [switch]$PrivilegeCommandsOnly, [switch]$SequencePrivilegesOnly, [switch]$CopyOnly, [switch]$AdvancedIndexesOnly, [switch]$SequencesOnly, [switch]$SequenceStateOnly, [switch]$SequenceOwnerOnly, [switch]$AccessibilityOnly, [switch]$ConnectionOnly, [switch]$StreamingOnly, [switch]$ExplorerOnly, [switch]$PropertiesOnly, [switch]$AcceptanceOnly, [ValidateRange(1024,65535)][int]$TestPort = 55439) $ErrorActionPreference = 'Stop' -if ((@($SessionsOnly, $PlansOnly, $ExportOnly, $ActivityOnly, $QueryStatisticsOnly, $GlobalBackupOnly, $ColumnTypesOnly, $IndexMaintenanceOnly, $IndexExpressionsOnly, $PartitionTablesOnly, $CascadeJournalOnly, $CascadeRoutinesOnly, $CascadeRollbackOnly, $RevokePreviewOnly, $GrantorConcurrencyOnly, $ExplicitGrantorOnly, $GrantorCatalogOnly, $DefaultProcessOnly, $DefaultDelegationOnly, $DefaultSchemasOnly, $DefaultTypesOnly, $DefaultRoutinesOnly, $DefaultSequencesOnly, $DefaultTablesOnly, $DefaultCancellationOnly, $DefaultUiOnly, $DefaultJournalOnly, $DefaultPrivilegesOnly, $RoutineBoundariesOnly, $RoutineProcessOnly, $RoutineConcurrencyOnly, $RoutinePrivilegesOnly, $BackupFormatsOnly, $IdentityColumnsOnly, $RestoreOwnershipOnly, $UnicodeBackupOnly, $PrivilegeJournalOnly, $MaintainPrivilegeOnly, $PrivilegeCommitOnly, $UnicodePasswordOnly, $MembershipOptionsOnly, $PrivilegeIdentityOnly, $ColumnPrivilegesOnly, $PrivilegeCancellationOnly, $EffectivePrivilegesOnly, $PrivilegeCommandsOnly, $SequencePrivilegesOnly, $CopyOnly, $AdvancedIndexesOnly, $SequencesOnly, $SequenceStateOnly, $SequenceOwnerOnly, $AccessibilityOnly, $ConnectionOnly, $StreamingOnly, $ExplorerOnly, $PropertiesOnly, $AcceptanceOnly) | Where-Object { $_ }).Count -gt 1) { throw 'Choose only one focused suite.' } +if ((@($ResultsTextOnly, $TableDesignOnly, $DiagramsOnly, $SessionsOnly, $PlansOnly, $ExportOnly, $ActivityOnly, $QueryStatisticsOnly, $GlobalBackupOnly, $ColumnTypesOnly, $IndexMaintenanceOnly, $IndexExpressionsOnly, $PartitionTablesOnly, $CascadeJournalOnly, $CascadeRoutinesOnly, $CascadeRollbackOnly, $RevokePreviewOnly, $GrantorConcurrencyOnly, $ExplicitGrantorOnly, $GrantorCatalogOnly, $DefaultProcessOnly, $DefaultDelegationOnly, $DefaultSchemasOnly, $DefaultTypesOnly, $DefaultRoutinesOnly, $DefaultSequencesOnly, $DefaultTablesOnly, $DefaultCancellationOnly, $DefaultUiOnly, $DefaultJournalOnly, $DefaultPrivilegesOnly, $RoutineBoundariesOnly, $RoutineProcessOnly, $RoutineConcurrencyOnly, $RoutinePrivilegesOnly, $BackupFormatsOnly, $IdentityColumnsOnly, $RestoreOwnershipOnly, $UnicodeBackupOnly, $PrivilegeJournalOnly, $MaintainPrivilegeOnly, $PrivilegeCommitOnly, $UnicodePasswordOnly, $ServerTlsOnly, $SchemaContextOnly, $MembershipOptionsOnly, $PrivilegeIdentityOnly, $ColumnPrivilegesOnly, $PrivilegeCancellationOnly, $EffectivePrivilegesOnly, $PrivilegeCommandsOnly, $SequencePrivilegesOnly, $CopyOnly, $AdvancedIndexesOnly, $SequencesOnly, $SequenceStateOnly, $SequenceOwnerOnly, $AccessibilityOnly, $ConnectionOnly, $StreamingOnly, $ExplorerOnly, $ReportsOnly, $PropertiesOnly, $AcceptanceOnly) | Where-Object { $_ }).Count -gt 1) { throw 'Choose only one focused suite.' } if ($DesktopOnly -and ($CascadeRoutinesOnly -or $CascadeRollbackOnly -or $RevokePreviewOnly -or $GrantorConcurrencyOnly -or $ExplicitGrantorOnly -or $GrantorCatalogOnly -or $DefaultDelegationOnly -or $DefaultSchemasOnly -or $DefaultTypesOnly -or $DefaultRoutinesOnly -or $DefaultSequencesOnly -or $DefaultTablesOnly -or $DefaultPrivilegesOnly -or $RoutineConcurrencyOnly -or $PrivilegeIdentityOnly -or $AcceptanceOnly -or $UnicodeBackupOnly)) { throw 'The selected focused suite has no desktop checks.' } $projectRoot = Split-Path $PSScriptRoot -Parent $testRoot = Join-Path $projectRoot 'artifacts\postgres-test' @@ -88,6 +88,8 @@ try { if ($MaintainPrivilegeOnly) { $testArgs = @("--", "--maintain-privilege") } if ($PrivilegeCommitOnly) { $testArgs = @("--", "--privilege-commit") } if ($UnicodePasswordOnly) { $testArgs = @("--", "--unicode-password") } + if ($ServerTlsOnly) { $testArgs = @("--", "--server-tls") } + if ($SchemaContextOnly) { $testArgs = @("--", "--schema-context") } if ($PrivilegeIdentityOnly) { $testArgs = @("--", "--privilege-identity") } if ($MembershipOptionsOnly) { $testArgs = @("--", "--membership-options") } if ($ColumnPrivilegesOnly) { $testArgs = @("--", "--column-privileges") } @@ -104,6 +106,10 @@ try { if ($AcceptanceOnly) { $testArgs = @("--", "--acceptance") } if ($PropertiesOnly) { $testArgs = @("--", "--properties") } if ($ExplorerOnly) { $testArgs = @("--", "--explorer") } + if ($ReportsOnly) { $testArgs = @("--", "--reports") } + if ($TableDesignOnly) { $testArgs = @("--", "--table-design") } + if ($DiagramsOnly) { $testArgs = @("--", "--diagrams") } + if ($ResultsTextOnly) { $testArgs = @("--", "--results-text") } if (!$CascadeJournalOnly -and !$DefaultProcessOnly -and !$DefaultCancellationOnly -and !$DefaultUiOnly -and !$DefaultJournalOnly -and !$RoutineBoundariesOnly -and !$RoutineProcessOnly -and !$DesktopOnly -and !$PrivilegeJournalOnly -and !$CopyOnly -and !$AccessibilityOnly -and !$ConnectionOnly -and !$ExplorerOnly) { dotnet run --project tests\PGMS.IntegrationTests\PGMS.IntegrationTests.csproj -c Release @testArgs if ($LASTEXITCODE -ne 0) { throw 'Integration checks failed' } diff --git a/src/PGMS.Desktop/AboutWindow.xaml b/src/PGMS.Desktop/AboutWindow.xaml index baa4bf4..57817c1 100644 --- a/src/PGMS.Desktop/AboutWindow.xaml +++ b/src/PGMS.Desktop/AboutWindow.xaml @@ -1,7 +1,7 @@ @@ -10,11 +10,20 @@ - - - - - + + + https://github.com/leoars + https://www.linkedin.com/in/leonardoars/ + Report an issue + + + View license + + Third-party notices + + + + diff --git a/src/PGMS.Desktop/AboutWindow.xaml.cs b/src/PGMS.Desktop/AboutWindow.xaml.cs index 8b355eb..ebf3cf5 100644 --- a/src/PGMS.Desktop/AboutWindow.xaml.cs +++ b/src/PGMS.Desktop/AboutWindow.xaml.cs @@ -1,13 +1,68 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; using System.Windows; +using System.Windows.Documents; +using System.Windows.Navigation; namespace PGMS.Desktop; public partial class AboutWindow : Window { + private const int MaxFolderLevels = 6; + + /// Opens a web address or a local file; replaced by tests. + internal Action OpenTarget { get; set; } = Launch; + public AboutWindow() { InitializeComponent(); - Milestone.Text = $"Development milestone {BuildInfo.Milestone}"; + ProductVersion.Text = VersionText(typeof(AboutWindow).Assembly.GetCustomAttribute()?.InformationalVersion); + } + + /// A build without a version set by the release process reports the SDK's default. + internal static string VersionText(string? informational) + { + string version = informational?.Split('+')[0] ?? ""; + return version.Length == 0 || version == "1.0.0" ? "Development build" : "Version " + version; + } + + private void OpenLink(object sender, RequestNavigateEventArgs e) + { + e.Handled = true; + Open(e.Uri.AbsoluteUri); + } + + private void OpenDocument(object sender, RoutedEventArgs e) + { + string name = (string)((Hyperlink)sender).Tag; + if (FindDocument(name) is { } path) Open(path); + else LinkStatus.Text = $"{name} was not found next to PGMS."; + } + + private void Open(string target) + { + try { LinkStatus.Text = ""; OpenTarget(target); } + catch (Exception ex) when (ex is Win32Exception or InvalidOperationException or FileNotFoundException) { LinkStatus.Text = "Could not open it: " + ex.Message; } + } + + private static void Launch(string target) + { + var start = File.Exists(target) ? new ProcessStartInfo("notepad.exe") { ArgumentList = { target } } : new ProcessStartInfo(target) { UseShellExecute = true }; + Process.Start(start)?.Dispose(); + } + + /// Packages keep these files next to the program; a build run from the repository finds them at its root. + internal static string? FindDocument(string name) + { + var folder = new DirectoryInfo(AppContext.BaseDirectory); + for (int level = 0; folder is not null && level <= MaxFolderLevels; level++, folder = folder.Parent) + { + string path = Path.Combine(folder.FullName, name); + if (File.Exists(path)) return path; + } + return null; } private void CloseAbout(object sender, RoutedEventArgs e) => Close(); diff --git a/src/PGMS.Desktop/AiProviderClient.cs b/src/PGMS.Desktop/AiProviderClient.cs new file mode 100644 index 0000000..4f31410 --- /dev/null +++ b/src/PGMS.Desktop/AiProviderClient.cs @@ -0,0 +1,70 @@ +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.Json; +using Anthropic; +using Anthropic.Exceptions; + +namespace PGMS.Desktop; + +/// Read-only provider calls. Listing models checks the key and address without generating text or spending tokens. +public static class AiProviderClient +{ + private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(20) }; + + public static async Task> ListModelsAsync(AiProviderSettings settings, CancellationToken token = default) + { + settings = settings.Validate(); + return settings.Provider switch + { + AiProvider.Anthropic => await ListAnthropicAsync(settings, token).ConfigureAwait(false), + AiProvider.OpenAI => await ListAsync(settings, "/models", "data", "id", token).ConfigureAwait(false), + _ => await ListAsync(settings, "/api/tags", "models", "name", token).ConfigureAwait(false) + }; + } + + private static async Task> ListAnthropicAsync(AiProviderSettings settings, CancellationToken token) + { + // Only the key saved in PGMS: the default constructor also picks up environment variables and + // `ant auth login` profiles, which would silently use another credential of this Windows user. + var client = new AnthropicClient { ApiKey = settings.RevealKey(), AuthToken = null, BaseUrl = settings.Endpoint }; + try + { + var page = await client.Models.List(cancellationToken: token).ConfigureAwait(false); + return page.Items.Select(m => m.ID).Order(StringComparer.Ordinal).ToArray(); + } + // Most specific first; SDK messages can include request details, so only a short cause is shown. + catch (AnthropicUnauthorizedException ex) { throw new AiProviderException("Anthropic rejected the API key (HTTP 401).", ex); } + catch (AnthropicForbiddenException ex) { throw new AiProviderException("The API key is not allowed to list models (HTTP 403).", ex); } + catch (AnthropicNotFoundException ex) { throw new AiProviderException("Anthropic address answered 404. Check the provider address.", ex); } + catch (AnthropicRateLimitException ex) { throw new AiProviderException("Anthropic rate limit reached. Try again shortly.", ex); } + catch (Anthropic5xxException ex) { throw new AiProviderException("Anthropic is temporarily unavailable (HTTP 5xx). Try again later.", ex); } + catch (AnthropicApiException ex) { throw new AiProviderException("Anthropic refused the request.", ex); } + catch (AnthropicIOException ex) { throw new AiProviderException("Could not reach Anthropic at " + settings.Endpoint + ".", ex); } + } + + private static async Task> ListAsync(AiProviderSettings settings, string path, string array, string field, CancellationToken token) + { + using var request = new HttpRequestMessage(HttpMethod.Get, settings.Endpoint + path); + if (settings.NeedsKey) request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", settings.RevealKey()); + try + { + using var response = await Http.SendAsync(request, token).ConfigureAwait(false); + string body = await response.Content.ReadAsStringAsync(token).ConfigureAwait(false); + if (!response.IsSuccessStatusCode) + throw new AiProviderException((int)response.StatusCode switch + { + 401 or 403 => $"{settings.Provider} rejected the API key (HTTP {(int)response.StatusCode}).", + 404 => $"{settings.Provider} address answered 404. Check the provider address.", + _ => $"{settings.Provider} answered HTTP {(int)response.StatusCode}." + }); + using var document = JsonDocument.Parse(body); + if (!document.RootElement.TryGetProperty(array, out var items) || items.ValueKind != JsonValueKind.Array) throw new AiProviderException($"{settings.Provider} returned an unexpected model list."); + return items.EnumerateArray().Select(i => i.TryGetProperty(field, out var v) ? v.GetString() : null).OfType().Order(StringComparer.Ordinal).ToArray(); + } + catch (HttpRequestException ex) { throw new AiProviderException($"Could not reach {settings.Provider} at {settings.Endpoint}: {ex.Message}", ex); } + catch (JsonException ex) { throw new AiProviderException($"{settings.Provider} returned a response that is not JSON.", ex); } + catch (TaskCanceledException ex) when (!token.IsCancellationRequested) { throw new AiProviderException($"{settings.Provider} did not answer within 20 seconds.", ex); } + } +} + +public sealed class AiProviderException(string message, Exception? inner = null) : Exception(message, inner); diff --git a/src/PGMS.Desktop/AiQueryDialog.xaml b/src/PGMS.Desktop/AiQueryDialog.xaml new file mode 100644 index 0000000..ae21a71 --- /dev/null +++ b/src/PGMS.Desktop/AiQueryDialog.xaml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + + + + + +