-
Notifications
You must be signed in to change notification settings - Fork 130
Merge develop into main for v0.5.1-rc.1 #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Introduces configurable path prefix to serve application under subpath (e.g., /pgbackweb) Implements validation for path prefixes in environment variables Updates all redirects and routes to use the configured path prefix This allows deploying the app at a custom URL path while maintaining correct functionality.
Updates tests to properly manage global state: - Uses defer pattern to restore original values after tests - Resets sync.Once to allow multiple SetPathPrefix calls in tests - Removes shouldSkip field from test cases as it's no longer needed
Refactors URL handling to allow serving the app from a subdirectory. Updates all static file paths and dashboard navigation links to use a utility function that prepends the configured path prefix when generating URLs.
Consistently uses the pathutil.BuildPath function to build URLs across various web components instead of hardcoding them.
Replaces string concatenation with fmt.Sprintf for building URLs This ensures consistent and more secure path handling across all dashboard operations like delete, edit, duplicate, etc.
Introduces consistent use of pathutil.BuildPath function for building URLs Adds proper path prefixing to image paths in support project data Improves URL generation across various dashboard components WIP on feature/path-prefix
Adds support for path prefix configuration
…configuration to include init-dialogs.js for content scanning
…onfirm for consistency
… community participation
|
Caution Review failedThe pull request is closed. WalkthroughAdds configurable PBW_PATH_PREFIX support with validation and a pathutil; updates startup, router, and many view files to build routes from the prefix. Replaces SweetAlert2 with a custom dialog module. Adds docs site, redirects, deploy workflow, README rebrand, sponsor updates, and minor static asset/config tweaks. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Start as App Start
participant Env as Env Loader
participant Val as validate.PathPrefix
participant PU as pathutil
participant Router as Router Init
participant Browser as Client
Start->>Env: read PBW_PATH_PREFIX
Env->>Val: validate prefix
Val-->>Env: result
Start->>PU: SetPathPrefix(value)
Router->>PU: GetPathPrefix()
Router->>Browser: serve routes under prefix (static, api, web)
sequenceDiagram
autonumber
participant User as User
participant UI as HTMX trigger
participant Dialog as customConfirm
participant Server as Backend
User->>UI: click destructive action
UI->>Dialog: window.customConfirm(text)
alt confirmed
Dialog-->>UI: {isConfirmed: true}
UI->>Server: HTMX request (DELETE/POST)
Server-->>UI: response
else dismissed
Dialog-->>UI: {isDismissed: true}
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (3)
internal/view/web/component/support_project.inc.js (1)
72-103: Consider cloning the data object before mutation.The method mutates the input
dataobject by reassigning its properties (lines 75, 83, 89, 95). If the originaldataobject is referenced elsewhere, this could lead to unexpected side effects.If data immutability is a concern, apply this diff to clone the data first:
processData(data) { + const clonedData = JSON.parse(JSON.stringify(data)); // Add path prefix to all image URLs - if (data.referralLinks) { - data.referralLinks = data.referralLinks.map((link) => ({ + if (clonedData.referralLinks) { + clonedData.referralLinks = clonedData.referralLinks.map((link) => ({ ...link, logo: this.prefixImagePath(link.logo), })); } - if (data.sponsors) { - if (data.sponsors.gold) { - data.sponsors.gold = data.sponsors.gold.map((sponsor) => ({ + if (clonedData.sponsors) { + if (clonedData.sponsors.gold) { + clonedData.sponsors.gold = clonedData.sponsors.gold.map((sponsor) => ({ ...sponsor, logo: this.prefixImagePath(sponsor.logo), })); } - if (data.sponsors.silver) { - data.sponsors.silver = data.sponsors.silver.map((sponsor) => ({ + if (clonedData.sponsors.silver) { + clonedData.sponsors.silver = clonedData.sponsors.silver.map((sponsor) => ({ ...sponsor, logo: this.prefixImagePath(sponsor.logo), })); } - if (data.sponsors.bronze) { - data.sponsors.bronze = data.sponsors.bronze.map((sponsor) => ({ + if (clonedData.sponsors.bronze) { + clonedData.sponsors.bronze = clonedData.sponsors.bronze.map((sponsor) => ({ ...sponsor, logo: this.prefixImagePath(sponsor.logo), })); } } - return data; + return clonedData; }internal/util/pathutil/pathutil_test.go (2)
58-59: Fragile state manipulation breaks encapsulation.Directly resetting unexported package variables (
pathPrefixandpathPrefixOnce) is fragile and breaks encapsulation. This pattern works only because the test is in the same package, but it makes the tests brittle and harder to maintain.Consider exposing a
ResetForTesting()function in the pathutil package (build-tagged for test files only) or restructuring to avoid global state where possible.Example approach with a test-only reset function in
pathutil.go://go:build test // +build test package pathutil func ResetForTesting() { pathPrefixOnce = sync.Once{} pathPrefix = "" }Then in the test:
t.Run(tt.name, func(t *testing.T) { - originalPrefix := pathPrefix - pathPrefixOnce = sync.Once{} + defer ResetForTesting() SetPathPrefix(tt.prefix) - defer func() { - pathPrefixOnce = sync.Once{} - pathPrefix = originalPrefix - }() result := BuildPath(tt.path)
76-76: Apply the same encapsulation improvement here.Similar to the previous comment on TestBuildPath, consider using a
ResetForTesting()function instead of directly manipulating unexported variables.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
assets/logos/hetzner-horizontal.pngis excluded by!**/*.pngassets/logos/hetzner.pngis excluded by!**/*.pnginternal/view/static/libs/sweetalert2/sweetalert2-11.13.1.min.jsis excluded by!**/*.min.js
📒 Files selected for processing (68)
.env.example(1 hunks).github/workflows/docs-deploy.yaml(1 hunks).prettierignore(1 hunks)README.md(5 hunks)assets/support-project-v1.json(2 hunks)cmd/app/main.go(3 hunks)docs/_redirects(1 hunks)docs/index.html(1 hunks)internal/config/env.go(1 hunks)internal/config/env_validate.go(1 hunks)internal/util/pathutil/pathutil.go(1 hunks)internal/util/pathutil/pathutil_test.go(1 hunks)internal/validate/path_prefix.go(1 hunks)internal/validate/path_prefix_test.go(1 hunks)internal/view/middleware/require_auth.go(2 hunks)internal/view/middleware/require_no_auth.go(2 hunks)internal/view/router.go(2 hunks)internal/view/static/css/partials/sweetalert2.css(0 hunks)internal/view/static/css/style.css(0 hunks)internal/view/static/js/app.js(1 hunks)internal/view/static/js/init-dialogs.js(1 hunks)internal/view/static/js/init-htmx.js(3 hunks)internal/view/static/js/init-sweetalert2.js(0 hunks)internal/view/static/static_fs.go(2 hunks)internal/view/web/auth/create_first_user.go(5 hunks)internal/view/web/auth/login.go(5 hunks)internal/view/web/auth/logout.go(3 hunks)internal/view/web/component/logotype.go(2 hunks)internal/view/web/component/support_project.inc.js(3 hunks)internal/view/web/dashboard/backups/create_backup.go(4 hunks)internal/view/web/dashboard/backups/delete_backup.go(2 hunks)internal/view/web/dashboard/backups/duplicate_backup.go(2 hunks)internal/view/web/dashboard/backups/edit_backup.go(2 hunks)internal/view/web/dashboard/backups/index.go(2 hunks)internal/view/web/dashboard/backups/list_backups.go(3 hunks)internal/view/web/dashboard/backups/manual_run.go(2 hunks)internal/view/web/dashboard/databases/create_database.go(2 hunks)internal/view/web/dashboard/databases/delete_database.go(2 hunks)internal/view/web/dashboard/databases/edit_database.go(2 hunks)internal/view/web/dashboard/databases/index.go(2 hunks)internal/view/web/dashboard/databases/list_databases.go(3 hunks)internal/view/web/dashboard/destinations/create_destination.go(2 hunks)internal/view/web/dashboard/destinations/delete_destination.go(2 hunks)internal/view/web/dashboard/destinations/edit_destination.go(2 hunks)internal/view/web/dashboard/destinations/index.go(2 hunks)internal/view/web/dashboard/destinations/list_destinations.go(3 hunks)internal/view/web/dashboard/executions/index.go(2 hunks)internal/view/web/dashboard/executions/list_executions.go(2 hunks)internal/view/web/dashboard/executions/restore_execution.go(3 hunks)internal/view/web/dashboard/executions/show_execution.go(2 hunks)internal/view/web/dashboard/executions/soft_delete_execution.go(2 hunks)internal/view/web/dashboard/profile/close_all_sessions.go(2 hunks)internal/view/web/dashboard/profile/update_user.go(2 hunks)internal/view/web/dashboard/restorations/index.go(2 hunks)internal/view/web/dashboard/restorations/list_restorations.go(2 hunks)internal/view/web/dashboard/webhooks/create_webhook.go(4 hunks)internal/view/web/dashboard/webhooks/delete_webhook.go(2 hunks)internal/view/web/dashboard/webhooks/duplicate_webhook.go(2 hunks)internal/view/web/dashboard/webhooks/edit_webhook.go(3 hunks)internal/view/web/dashboard/webhooks/index.go(2 hunks)internal/view/web/dashboard/webhooks/list_webhooks.go(2 hunks)internal/view/web/dashboard/webhooks/run_webhook.go(2 hunks)internal/view/web/dashboard/webhooks/webhook_executions.go(3 hunks)internal/view/web/layout/common.go(2 hunks)internal/view/web/layout/dashboard_aside.go(3 hunks)internal/view/web/layout/dashboard_header.go(2 hunks)internal/view/web/router.go(3 hunks)tailwind.config.ts(1 hunks)
💤 Files with no reviewable changes (3)
- internal/view/static/css/partials/sweetalert2.css
- internal/view/static/js/init-sweetalert2.js
- internal/view/static/css/style.css
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Use structured logging with logger.KV{"key": value} for context
Use logger.FatalError() for startup failures
Files:
internal/view/web/dashboard/webhooks/create_webhook.gointernal/view/web/dashboard/databases/index.gointernal/view/web/dashboard/backups/create_backup.gointernal/view/web/dashboard/webhooks/run_webhook.gointernal/view/web/auth/create_first_user.gointernal/config/env_validate.gointernal/view/web/dashboard/webhooks/list_webhooks.gointernal/view/web/router.gointernal/view/web/dashboard/backups/delete_backup.gocmd/app/main.gointernal/view/web/layout/dashboard_aside.gointernal/view/web/auth/logout.gointernal/view/web/dashboard/backups/duplicate_backup.gointernal/validate/path_prefix.gointernal/view/web/dashboard/webhooks/webhook_executions.gointernal/view/web/dashboard/databases/edit_database.gointernal/util/pathutil/pathutil_test.gointernal/util/pathutil/pathutil.gointernal/view/web/dashboard/restorations/index.gointernal/view/web/dashboard/backups/list_backups.gointernal/view/middleware/require_auth.gointernal/view/web/dashboard/executions/soft_delete_execution.gointernal/view/web/dashboard/backups/edit_backup.gointernal/validate/path_prefix_test.gointernal/view/web/dashboard/webhooks/index.gointernal/view/web/auth/login.gointernal/view/web/layout/dashboard_header.gointernal/view/web/dashboard/webhooks/duplicate_webhook.gointernal/view/web/dashboard/databases/create_database.gointernal/view/web/dashboard/backups/index.gointernal/view/web/dashboard/databases/list_databases.gointernal/view/web/dashboard/backups/manual_run.gointernal/view/web/dashboard/destinations/list_destinations.gointernal/view/static/static_fs.gointernal/view/middleware/require_no_auth.gointernal/view/web/dashboard/restorations/list_restorations.gointernal/view/web/dashboard/profile/close_all_sessions.gointernal/view/web/component/logotype.gointernal/view/web/dashboard/destinations/create_destination.gointernal/view/web/dashboard/profile/update_user.gointernal/view/web/dashboard/databases/delete_database.gointernal/view/web/dashboard/executions/restore_execution.gointernal/view/web/dashboard/destinations/index.gointernal/view/web/dashboard/webhooks/delete_webhook.gointernal/view/web/dashboard/webhooks/edit_webhook.gointernal/view/web/dashboard/executions/list_executions.gointernal/view/web/layout/common.gointernal/view/web/dashboard/destinations/delete_destination.gointernal/view/web/dashboard/destinations/edit_destination.gointernal/view/web/dashboard/executions/show_execution.gointernal/view/web/dashboard/executions/index.gointernal/view/router.gointernal/config/env.go
internal/view/**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
Access request context via internal/view/reqctx in web handlers
Files:
internal/view/web/dashboard/webhooks/create_webhook.gointernal/view/web/dashboard/databases/index.gointernal/view/web/dashboard/backups/create_backup.gointernal/view/web/dashboard/webhooks/run_webhook.gointernal/view/web/auth/create_first_user.gointernal/view/web/dashboard/webhooks/list_webhooks.gointernal/view/web/router.gointernal/view/web/dashboard/backups/delete_backup.gointernal/view/web/layout/dashboard_aside.gointernal/view/web/auth/logout.gointernal/view/web/dashboard/backups/duplicate_backup.gointernal/view/web/dashboard/webhooks/webhook_executions.gointernal/view/web/dashboard/databases/edit_database.gointernal/view/web/dashboard/restorations/index.gointernal/view/web/dashboard/backups/list_backups.gointernal/view/middleware/require_auth.gointernal/view/web/dashboard/executions/soft_delete_execution.gointernal/view/web/dashboard/backups/edit_backup.gointernal/view/web/dashboard/webhooks/index.gointernal/view/web/auth/login.gointernal/view/web/layout/dashboard_header.gointernal/view/web/dashboard/webhooks/duplicate_webhook.gointernal/view/web/dashboard/databases/create_database.gointernal/view/web/dashboard/backups/index.gointernal/view/web/dashboard/databases/list_databases.gointernal/view/web/dashboard/backups/manual_run.gointernal/view/web/dashboard/destinations/list_destinations.gointernal/view/static/static_fs.gointernal/view/middleware/require_no_auth.gointernal/view/web/dashboard/restorations/list_restorations.gointernal/view/web/dashboard/profile/close_all_sessions.gointernal/view/web/component/logotype.gointernal/view/web/dashboard/destinations/create_destination.gointernal/view/web/dashboard/profile/update_user.gointernal/view/web/dashboard/databases/delete_database.gointernal/view/web/dashboard/executions/restore_execution.gointernal/view/web/dashboard/destinations/index.gointernal/view/web/dashboard/webhooks/delete_webhook.gointernal/view/web/dashboard/webhooks/edit_webhook.gointernal/view/web/dashboard/executions/list_executions.gointernal/view/web/layout/common.gointernal/view/web/dashboard/destinations/delete_destination.gointernal/view/web/dashboard/destinations/edit_destination.gointernal/view/web/dashboard/executions/show_execution.gointernal/view/web/dashboard/executions/index.gointernal/view/router.go
internal/config/env_validate.go
📄 CodeRabbit inference engine (AGENTS.md)
Perform configuration validation in internal/config/env_validate.go
Files:
internal/config/env_validate.go
**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*_test.go: Write table-driven tests using t.Run with a slice of structs
Mark reusable test helper functions with t.Helper()
Files:
internal/util/pathutil/pathutil_test.gointernal/validate/path_prefix_test.go
internal/util/**/*_test.go
📄 CodeRabbit inference engine (AGENTS.md)
Provide comprehensive test coverage for packages under internal/util/
Files:
internal/util/pathutil/pathutil_test.go
internal/view/router.go
📄 CodeRabbit inference engine (AGENTS.md)
Mount web and API routes in internal/view/router.go using Echo
Files:
internal/view/router.go
internal/config/env.go
📄 CodeRabbit inference engine (AGENTS.md)
Load environment-based configuration in internal/config/env.go
Files:
internal/config/env.go
🧠 Learnings (5)
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/config/env_validate.go : Perform configuration validation in internal/config/env_validate.go
Applied to files:
internal/config/env_validate.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/view/**/*.go : Access request context via internal/view/reqctx in web handlers
Applied to files:
internal/view/web/auth/logout.gointernal/view/web/dashboard/backups/manual_run.gointernal/view/middleware/require_no_auth.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/util/**/*_test.go : Provide comprehensive test coverage for packages under internal/util/
Applied to files:
internal/util/pathutil/pathutil_test.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Require env vars PBW_ENCRYPTION_KEY and PBW_POSTGRES_CONN_STRING; support optional PBW_LISTEN_HOST, PBW_LISTEN_PORT, TZ
Applied to files:
.env.exampleREADME.mdinternal/config/env.go
📚 Learning: 2025-10-05T19:11:29.823Z
Learnt from: CR
PR: eduardolat/pgbackweb#0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T19:11:29.823Z
Learning: Applies to internal/view/router.go : Mount web and API routes in internal/view/router.go using Echo
Applied to files:
internal/view/router.go
🧬 Code graph analysis (53)
internal/view/web/dashboard/webhooks/create_webhook.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/databases/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/static/js/app.js (2)
internal/view/static/js/init-dialogs.js (1)
initDialogs(1-137)internal/view/static/js/init-sweetalert2.js (3)
initSweetAlert2(1-34)swalAlert(15-20)swalConfirm(22-30)
internal/view/web/dashboard/backups/create_backup.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/webhooks/run_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/auth/create_first_user.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/config/env_validate.go (1)
internal/validate/path_prefix.go (1)
PathPrefix(21-43)
internal/view/web/dashboard/webhooks/list_webhooks.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/router.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/delete_backup.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
cmd/app/main.go (1)
internal/util/pathutil/pathutil.go (2)
SetPathPrefix(12-16)GetPathPrefix(19-21)
internal/view/web/layout/dashboard_aside.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/static/js/init-dialogs.js (1)
internal/view/static/js/init-sweetalert2.js (3)
swalAlert(15-20)swalConfirm(22-30)initSweetAlert2(1-34)
internal/view/web/auth/logout.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/duplicate_backup.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/webhooks/webhook_executions.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/databases/edit_database.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/util/pathutil/pathutil_test.go (1)
internal/util/pathutil/pathutil.go (3)
SetPathPrefix(12-16)BuildPath(30-35)GetPathPrefix(19-21)
internal/view/web/dashboard/restorations/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/list_backups.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/middleware/require_auth.go (2)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)
internal/view/web/dashboard/executions/soft_delete_execution.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/edit_backup.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/validate/path_prefix_test.go (1)
internal/validate/path_prefix.go (1)
PathPrefix(21-43)
internal/view/web/dashboard/webhooks/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/auth/login.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/layout/dashboard_header.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/webhooks/duplicate_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/databases/create_database.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/databases/list_databases.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/backups/manual_run.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/destinations/list_destinations.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/static/static_fs.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/middleware/require_no_auth.go (2)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)
internal/view/web/dashboard/restorations/list_restorations.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/profile/close_all_sessions.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/component/logotype.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/destinations/create_destination.go (2)
internal/view/web/respondhtmx/respond.go (1)
Redirect(78-82)internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/profile/update_user.go (2)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)internal/view/web/dashboard/profile/index.go (2)
indexPage(31-46)h(16-29)
internal/view/web/dashboard/databases/delete_database.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/executions/restore_execution.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/destinations/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/webhooks/delete_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/webhooks/edit_webhook.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/static/js/init-htmx.js (1)
internal/view/static/js/init-sweetalert2.js (1)
swalConfirm(22-30)
internal/view/web/dashboard/executions/list_executions.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/layout/common.go (1)
internal/util/pathutil/pathutil.go (1)
GetPathPrefix(19-21)
internal/view/web/dashboard/destinations/delete_destination.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/destinations/edit_destination.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/executions/show_execution.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/web/dashboard/executions/index.go (1)
internal/util/pathutil/pathutil.go (1)
BuildPath(30-35)
internal/view/router.go (7)
internal/util/pathutil/pathutil.go (1)
GetPathPrefix(19-21)internal/view/middleware/browser_cache.go (1)
BrowserCacheMiddlewareConfig(10-13)internal/view/static/static_fs.go (1)
StaticFs(12-12)internal/logger/logger.go (1)
FatalError(70-73)internal/logger/kv.go (1)
KV(6-6)internal/view/web/router.go (1)
MountRouter(16-50)internal/view/api/router.go (1)
MountRouter(13-22)
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 17-17: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
🪛 markdownlint-cli2 (0.18.1)
README.md
120-120: Images should have alternate text (alt text)
(MD045, no-alt-text)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Lint, test, and build the code (ubuntu-24.04-arm, linux/arm64)
- GitHub Check: Lint, test, and build the code (ubuntu-24.04, linux/amd64)
- GitHub Check: Lint, test, and build the code (ubuntu-24.04-arm, linux/arm64)
- GitHub Check: Lint, test, and build the code (ubuntu-24.04, linux/amd64)
🔇 Additional comments (60)
internal/view/web/component/support_project.inc.js (2)
105-134: LGTM! Consistent data processing.The changes ensure that both cached and freshly fetched data are processed uniformly through
processData(), guaranteeing that logo paths are correctly prefixed regardless of the data source.
58-70: No changes required:window.PBW_PATH_PREFIXis always defined with default empty string.internal/view/web/dashboard/executions/list_executions.go (1)
11-11: LGTM! Consistent path prefix integration.The import of
pathutiland usage ofBuildPathfor URL construction aligns with the project-wide refactoring to support configurable path prefixes. The change is minimal and correct.Also applies to: 121-121
.prettierignore (1)
2-2: LGTM! Build directory properly excluded.Adding the build directory to Prettier's ignore list is appropriate and follows standard practices for excluding generated artifacts.
internal/view/web/dashboard/destinations/index.go (1)
7-7: LGTM! Path prefix integration applied correctly.The addition of
pathutilimport and use ofBuildPathin the HxGet attribute follows the consistent pattern established across the codebase for supporting configurable path prefixes.Also applies to: 59-59
internal/view/web/dashboard/executions/restore_execution.go (1)
10-10: LGTM! Restore workflow paths updated consistently.Both the form submission (HxPost) and form loading (HxGet) endpoints now use
pathutil.BuildPath, ensuring consistent path prefix handling throughout the restoration workflow.Also applies to: 111-111, 226-226
internal/view/web/dashboard/backups/duplicate_backup.go (1)
4-6: LGTM! Duplicate action path construction updated.The necessary imports (
fmt,pathutil) are added andBuildPathis used correctly in the duplicate button to support path prefixing.Also applies to: 33-33
internal/view/web/dashboard/backups/list_backups.go (1)
11-11: LGTM! Navigation and pagination paths updated consistently.Both the executions link and pagination URLs now use
pathutil.BuildPath, ensuring proper path prefix handling across backup list navigation.Also applies to: 74-76, 129-131
docs/_redirects (2)
2-2: Verify the community redirect URL.The community redirect points to
https://ufobackup.uforg.dev, which appears to reference a different project name (ufobackup) than the repository (pgbackweb). Please confirm this is the intended URL or if it should be updated to match the project's domain.
3-8: LGTM! Redirect aliases provide convenient shorthand URLs.The redirect mappings for project and author links are well-structured, with aliases (e.g.,
/r/twitterand/r/x) providing flexible shorthand URLs for external resources.Also applies to: 11-15
internal/view/web/dashboard/destinations/delete_destination.go (1)
4-6: LGTM! Delete action path construction updated.The necessary imports are added and
pathutil.BuildPathis correctly used in the delete button to support configurable path prefixes.Also applies to: 34-34
internal/view/web/dashboard/webhooks/edit_webhook.go (2)
106-106: Pathutil integration aligns with prefixed routes.Switching the form action to
pathutil.BuildPathcorrectly folds in the configured dashboard prefix.
131-131: Consistent modal fetch URL.Using
pathutil.BuildPathhere keeps the edit modal loader in sync with the global prefix handling.internal/view/web/dashboard/webhooks/create_webhook.go (3)
58-58: Redirect respects path prefix.Good call swapping to
pathutil.BuildPath; the post-create redirect now honors any configured base path.
90-90: Prefixed form submission.Using
pathutil.BuildPathhere keeps the create form POST aligned with the global prefix handling.
115-115: Prefixed modal loader.The modal fetch now routes through
pathutil.BuildPath, matching the rest of the prefix-aware endpoints.internal/view/web/dashboard/webhooks/webhook_executions.go (2)
92-94: Next-page URL honors prefix.Wrapping the executions endpoint in
pathutil.BuildPathkeeps infinite scroll working under a custom base path.
262-263: Modal fetch aligned with prefixed routing.The initial executions load now goes through
pathutil.BuildPath, so path prefixes are consistently applied.tailwind.config.ts (1)
6-9: Tailwind now scans dialog scripts.Including
init-dialogs.jsin the content list ensures any dialog utility classes survive purging. 👍internal/view/static/js/init-htmx.js (1)
9-24: Custom dialog promise contract confirmed window.customAlert and window.customConfirm resolve to{isConfirmed, isDismissed}as expected, so.then(...)usage is safe.internal/validate/path_prefix.go (1)
21-43: LGTM!The validation logic is correct and well-documented. The implementation properly validates:
- Empty string as valid (no prefix)
- Required leading slash
- No trailing slash
- No whitespace
The code is clear and maintainable.
docs/index.html (1)
47-51: Verify the hardcoded version tag in the logo URL.The logo image URL references a specific git tag (v0.5.0). This means the logo won't update automatically with new versions of the application. Confirm this is intentional for version stability, or consider using a branch reference (e.g.,
refs/heads/main) to automatically reflect the latest logo.internal/util/pathutil/pathutil.go (2)
10-16: LGTM!The use of
sync.Onceensures thread-safe initialization and prevents the path prefix from being changed after initial setup. This is the correct pattern for application-level configuration.
30-35: Consider documenting the caller's responsibility for path format.
BuildPathconcatenates the prefix and path without validating thatpathstarts with/. If a caller passes"dashboard"instead of"/dashboard", the result would be malformed (e.g.,"/pgbackwebdashboard"instead of"/pgbackweb/dashboard").While this may be intentional (placing responsibility on the caller), consider adding a note in the documentation or a panic/validation check to catch this common mistake during development.
For example, you could add validation like:
func BuildPath(path string) string { if pathPrefix == "" { return path } + if path != "" && !strings.HasPrefix(path, "/") { + panic(fmt.Sprintf("BuildPath: path must start with / or be empty, got: %s", path)) + } return pathPrefix + path }internal/view/web/dashboard/destinations/edit_destination.go (1)
62-62: LGTM!The update correctly applies the path prefix to the HTMX post URL, consistent with the broader path prefix support introduced across the codebase.
internal/view/web/dashboard/backups/edit_backup.go (1)
94-94: LGTM!The change correctly applies the path prefix to the dynamically constructed edit URL. The path is properly formatted with a leading slash before being passed to
BuildPath.internal/view/web/dashboard/webhooks/list_webhooks.go (1)
95-99: LGTM!The change correctly applies the path prefix to the pagination URL. The query parameters are properly added after building the base path, maintaining the existing pagination logic.
internal/view/web/dashboard/webhooks/run_webhook.go (1)
48-48: LGTM!The change correctly applies the path prefix to the webhook run endpoint URL. The path is properly formatted with a leading slash before being passed to
BuildPath.internal/view/web/dashboard/webhooks/duplicate_webhook.go (1)
4-6: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor URL construction is correct and enables configurable path prefix for subpath deployments. The pattern is consistent with similar changes across the codebase.Also applies to: 33-33
internal/view/web/dashboard/executions/show_execution.go (1)
4-4: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor the download button href is correct and consistent with the broader refactor to support configurable path prefixes across the application.Also applies to: 9-9, 126-126
internal/view/web/dashboard/webhooks/delete_webhook.go (1)
4-6: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor the delete webhook URL is correct and follows the established pattern for enabling path prefix configuration.Also applies to: 33-33
internal/view/web/dashboard/destinations/create_destination.go (1)
5-5: LGTM! Consistent path prefix support.The migration of both the redirect path and form action URLs to
pathutil.BuildPathis correct and consistent with the broader refactor to support configurable path prefixes.Also applies to: 49-49, 55-55
internal/view/web/dashboard/backups/manual_run.go (1)
5-5: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor the manual run URL is correct and consistent with the established pattern for enabling path prefix configuration.Also applies to: 7-7, 32-32
internal/view/web/dashboard/executions/soft_delete_execution.go (1)
4-6: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor the delete execution URL is correct and follows the established pattern for enabling path prefix configuration.Also applies to: 34-34
internal/view/web/dashboard/backups/create_backup.go (1)
10-10: LGTM! Consistent path prefix support.The migration of redirect, form action, and HTMX trigger URLs to
pathutil.BuildPathis correct and consistent. All URL construction points in this file have been properly updated to support configurable path prefixes.Also applies to: 74-74, 109-109, 326-326
internal/view/web/dashboard/backups/delete_backup.go (1)
4-6: LGTM! Consistent path prefix support.The migration to
pathutil.BuildPathfor the delete backup URL is correct and follows the established pattern for enabling path prefix configuration.Also applies to: 33-33
internal/view/web/layout/dashboard_aside.go (1)
6-6: LGTM! Consistent path prefix integration.The migration to
pathutil.BuildPath()for all navigation links and assets is correctly implemented and aligns with the centralized path prefix mechanism introduced across the codebase.Also applies to: 26-26, 49-105
internal/view/web/dashboard/destinations/list_destinations.go (1)
11-11: LGTM! Path construction properly updated.The use of
pathutil.BuildPath()for the executions link, test connection endpoint, and pagination URL is correct. Including query parameters within the path string works as expected with the path prefix mechanism.Also applies to: 66-136
internal/view/web/dashboard/databases/list_databases.go (1)
11-11: LGTM! Consistent with path prefix refactor.The changes mirror the pattern used in the destinations file and correctly apply path prefix handling to executions links, test actions, and pagination.
Also applies to: 68-110
README.md (1)
32-37: Good addition of path prefix documentation.The documentation for
PBW_PATH_PREFIXclearly explains its purpose and usage constraints (must start with/, not end with/). The rebranding note and feature updates improve clarity.Also applies to: 114-114
internal/view/web/dashboard/profile/close_all_sessions.go (1)
5-5: LGTM! Logout action correctly uses path prefix.The logout endpoint now correctly respects the configured path prefix.
Also applies to: 19-19
internal/view/web/layout/common.go (1)
4-4: LGTM! Smart client-side path prefix injection.Exposing
window.PBW_PATH_PREFIXas a global JavaScript variable enables client-side code to construct URLs that respect the configured path prefix. This bridges server-side and client-side path handling effectively.Also applies to: 36-37
internal/view/web/dashboard/backups/index.go (1)
7-7: LGTM! Initial list load uses path prefix correctly.The backup list endpoint correctly uses
pathutil.BuildPath()for the initial HTMX load trigger.Also applies to: 54-54
internal/view/middleware/require_no_auth.go (1)
6-6: LGTM! Redirect consistency maintained.Using the same
redirectPathconstructed viaBuildPath()for both the HTMX header redirect and HTTP redirect ensures consistent behavior across both navigation mechanisms.Also applies to: 17-19
internal/view/web/auth/logout.go (1)
4-4: LGTM!Clean migration to centralized path construction via
pathutil.BuildPath. The logout handlers now correctly support configurable path prefixes while preserving existing redirect behavior.Also applies to: 19-19, 32-32
internal/view/web/dashboard/databases/index.go (1)
7-7: LGTM!The migration to
pathutil.BuildPathfor the HTMX endpoint is correct and preserves the query parameters.Also applies to: 46-46
internal/view/static/js/app.js (1)
2-2: LGTM!Clean migration from SweetAlert2 to the custom dialogs system. The new implementation exposes compatible global APIs (
window.customAlert,window.customConfirm) and removes an external dependency.Also applies to: 8-8
.env.example (1)
15-17: LGTM!The new
PBW_PATH_PREFIXenvironment variable is well-documented with a clear example. The static analysis warning about quote characters is a false positive—the empty quotes are intentional in an example file to demonstrate the expected format.internal/view/web/component/logotype.go (1)
4-4: LGTM!The logotype component now correctly uses
pathutil.BuildPathfor the logo image source, ensuring it works under configurable path prefixes.Also applies to: 16-16
internal/view/web/dashboard/databases/create_database.go (1)
7-7: LGTM!The migration to
pathutil.BuildPathis correct for both the post-creation redirect and the HTMX form submission endpoints. All URL construction is now centralized.Also applies to: 45-45, 51-51
internal/view/web/dashboard/restorations/index.go (1)
7-7: LGTM!The base URL construction now correctly uses
pathutil.BuildPath, while preserving the existing query parameter logic withstrutil.AddQueryParamToUrl. This ensures the path prefix is applied before adding query parameters.Also applies to: 70-70
internal/view/web/dashboard/databases/edit_database.go (1)
7-7: LGTM!The HTMX form submission endpoints now correctly use
pathutil.BuildPathfor centralized URL construction, consistent with the create database handler.Also applies to: 59-59
internal/view/web/dashboard/restorations/list_restorations.go (1)
113-113: LGTM!The path construction correctly uses
pathutil.BuildPathand appends query parameters afterward, maintaining compatibility with the pagination and filtering logic.internal/view/web/router.go (1)
25-42: LGTM!All redirect paths correctly utilize
pathutil.BuildPath, ensuring consistent path prefix handling across authentication flows and dashboard navigation.internal/view/web/dashboard/webhooks/index.go (1)
49-49: LGTM!The path construction correctly uses
pathutil.BuildPathwith the query parameter included in the path string, which is appropriate sinceBuildPathonly prepends the configured prefix.internal/config/env.go (1)
15-15: LGTM!The
PBW_PATH_PREFIXfield is properly defined following the existing environment variable pattern, with an empty default value making the path prefix optional as intended.internal/config/env_validate.go (1)
19-21: LGTM!The path prefix validation is correctly implemented using
validate.PathPrefix, with a clear error message that accurately describes the validation rules (must start with/, must not end with/, or be empty). As per coding guidelines.internal/view/web/dashboard/profile/update_user.go (1)
52-52: LGTM!The form submission path correctly uses
pathutil.BuildPath, ensuring the profile update form works correctly when the application is served under a path prefix.internal/view/middleware/require_auth.go (1)
33-40: LGTM!The redirect logic correctly handles both HTMX-based and browser-based redirects consistently by using
pathutil.BuildPathfor bothhtmx.ServerSetRedirectandc.Redirect, ensuring proper navigation regardless of the request type.internal/view/static/static_fs.go (1)
32-46: LGTM!The implementation correctly prepends the path prefix before appending the version query parameter, ensuring static files are properly referenced when the application is served under a subpath. The added comments clearly document the integration with the path prefix system.
| "logo": "https://raw.githubusercontent.com/eduardolat/pgbackweb/refs/heads/develop/assets/logos/hetzner-horizontal.png", | ||
| "link": "https://hetzner.cloud/?ref=TdOypLgK8yGR", | ||
| "description": "Get started with Hetzner Cloud today and enjoy €20 in free credits just for signing up through this link! Their powerful cloud servers offer excellent performance at competitive prices. After you spend your first €10, I'll receive €10 in credits too, making it a win-win for both of us!" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid hotlinking logos from a mutable GitHub branch
Both the Hetzner and FetchGoat logos point to raw.githubusercontent.com/.../refs/heads/develop/.... Those URLs rely on the branch name existing forever and will 404 or change unexpectedly if the branch is renamed, deleted, or the repo reorganizes assets—breaking the images in production. Please add the logo files to the deployed static assets (as you do with other logos) or pin the URLs to an immutable location (e.g., a tagged release or CDN).
Also applies to: 45-46
🤖 Prompt for AI Agents
In assets/support-project-v1.json around lines 11-13 (also apply same change to
lines 45-46), the logo URLs hotlink to raw.githubusercontent.com with a branch
ref which can break if the branch is renamed or removed; replace those fragile
external links by either (A) adding the Hetzner and FetchGoat logo files into
the project's deployed static assets folder and updating the JSON to point to
the local/static asset paths, or (B) pinning the external URLs to an immutable
location (e.g., a tagged release URL or a CDN/GitHub release asset URL) so the
links won’t change; ensure you add the files to the repo, update the JSON
entries, and verify the assets are included in the build/deploy pipeline.
| ) | ||
|
|
||
| func TestBuildPath(t *testing.T) { | ||
| t.Helper() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove misplaced t.Helper() call.
According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.
Apply this diff:
func TestBuildPath(t *testing.T) {
- t.Helper()
-
tests := []struct {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| t.Helper() | |
| func TestBuildPath(t *testing.T) { | |
| tests := []struct { | |
| name string | |
| prefix string | |
| path string | |
| want string | |
| }{ | |
| // test cases... | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| // ... | |
| }) | |
| } | |
| } |
🤖 Prompt for AI Agents
In internal/util/pathutil/pathutil_test.go around line 9, the test contains a
misplaced t.Helper() call; remove the t.Helper() invocation from the test
function body so only actual helper functions use t.Helper(); if you intended to
mark a helper, move the t.Helper() call into that helper function instead and
leave the test function without it.
| } | ||
|
|
||
| func TestGetPathPrefix(t *testing.T) { | ||
| t.Helper() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove misplaced t.Helper() call.
According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.
Apply this diff:
func TestGetPathPrefix(t *testing.T) {
- t.Helper()
originalPrefix := pathPrefix🤖 Prompt for AI Agents
internal/util/pathutil/pathutil_test.go around line 74: the test contains a
misplaced call to t.Helper() on the test function itself; remove the t.Helper()
invocation from this test (delete the line at 74) so that t.Helper() is only
used inside reusable helper functions.
| import "testing" | ||
|
|
||
| func TestPathPrefix(t *testing.T) { | ||
| t.Helper() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove misplaced t.Helper() call.
According to the coding guidelines, t.Helper() should only be marked on reusable test helper functions, not on the test function itself.
Apply this diff:
func TestPathPrefix(t *testing.T) {
- t.Helper()
-
tests := []struct {🤖 Prompt for AI Agents
internal/validate/path_prefix_test.go around line 6: the test function contains
a misplaced t.Helper() call which should only be used inside reusable helper
functions; remove the t.Helper() invocation from the test function so it is no
longer called at this location (leave helper functions' t.Helper() unchanged if
present).
| backdrop.onclick = () => closeDialog(dialogId, resolve, !isConfirm); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backdrop/ESC dismissal flips confirmation state
When showing an alert (isConfirm === false), both the backdrop click (Line 56) and ESC handler (Line 110) resolve with !isConfirm, i.e., true. That incorrectly marks dismissals as confirmations, diverging from the previous SweetAlert2 semantics and can falsely signal user acknowledgement. Please resolve dismissals with false instead.
- backdrop.onclick = () => closeDialog(dialogId, resolve, !isConfirm);
+ backdrop.onclick = () => closeDialog(dialogId, resolve, false);
...
- closeDialog(dialogId, resolve, !isConfirm);
+ closeDialog(dialogId, resolve, false);Also applies to: 109-111
🤖 Prompt for AI Agents
In internal/view/static/js/init-dialogs.js around lines 56-57 and 109-111, the
backdrop click and ESC key handlers call closeDialog(..., !isConfirm) so
dismissals are treated as confirmations when isConfirm is false; change those
calls to resolve dismissals as false (e.g., use closeDialog(dialogId, resolve,
false)) so clicking the backdrop or pressing ESC always resolves as a dismissal
(false) rather than flipping the confirmation state.
|
|
||
| ## Screenshot | ||
|
|
||
| <img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add alt text to the screenshot image.
The screenshot image is missing alternative text, which affects accessibility for screen reader users.
Apply this diff to add descriptive alt text:
-<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" />
+<img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" alt="PG Back Web dashboard interface showing backup management features" />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" /> | |
| <img src="https://raw.githubusercontent.com/eduardolat/pgbackweb/main/assets/screenshot.png" alt="PG Back Web dashboard interface showing backup management features" /> |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
120-120: Images should have alternate text (alt text)
(MD045, no-alt-text)
🤖 Prompt for AI Agents
In README.md around line 120 the screenshot <img> tag lacks alt text which harms
accessibility; update the tag to include a concise, descriptive alt attribute
(for example: alt="pgbackweb web UI showing dashboard and navigation with
database list and query results") so screen readers can convey the image
content.
Summary by CodeRabbit
New Features
Documentation
Chores
Tests