Skip to content

✨ feat(ui): clickable port links, keyboard shortcuts, live uptime - #676

Merged
scttbnsn merged 4 commits into
dev/v1.7from
feat/v1.7-ui-quickwins
Aug 8, 2026
Merged

✨ feat(ui): clickable port links, keyboard shortcuts, live uptime#676
scttbnsn merged 4 commits into
dev/v1.7from
feat/v1.7-ui-quickwins

Conversation

@scttbnsn

@scttbnsn scttbnsn commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Three v1.7 roadmap quick wins (6.2, 6.7, 6.8) closing visible UI gaps against Dockhand/Portainer/Arcane.

Clickable port links (6.2)

  • Host-published ports render as new-tab links (rel="noopener noreferrer") in the container table (opt-in column), card views, and all three detail surfaces; internal-only ports stay plain text.
  • Protocol auto-detect (443/8443 → https), new pure ui/src/utils/ports.ts for parse/scheme/link/label logic.
  • New dd.port.label container label for custom display names, threaded through the label-override pipeline into a new Container.portLabel field (follows the linkTemplate/displayName precedent). Documented in the watcher label table.
  • useAgentHosts() composable so agent-watched containers link against the right host.

Keyboard shortcuts (6.7)

  • / focuses search from anywhere, Escape closes it, ? opens a shortcut reference overlay (styled after ConfirmDialog). useKeyboardShortcuts() + useShortcutsOverlay() composables; / hint alongside the existing ⌘K hint.

Container uptime (6.8)

  • details.startedAt was already in the payload; the list-view uptime cell gains an exact-timestamp tooltip and the card footer a live "Up …" indicator, both timer-refreshed, matching the detail-page display. Also documented the previously-undocumented details.startedAt field.

Testing

  • app/: 12,567 tests, 100% coverage; ui/: 4,421 tests across 219 files, 100% coverage; lint + build clean in both
  • Full lefthook pre-push gate passed

Changelog

  • ✨ Added clickable published-port links with HTTP/HTTPS detection, IPv4/IPv6 support, agent-host resolution, and dd.port.label overrides.
  • ✨ Added live container uptime indicators and exact start-time tooltips for list and card views.
  • ✨ Added /, Escape, and ? keyboard shortcuts with a localized shortcut reference overlay.
  • ✨ Added an optional ports container-table column with responsive visibility and overflow handling.
  • ✨ Added Docker label parsing, port enrichment utilities, watcher documentation, and comprehensive tests.
  • 🔧 Extended container models and API mapping with agent and portLabel.
  • 🔧 Added shared, deduplicated agent-host loading and fallback resolution through useAgentHosts.
  • 🔧 Updated search hints and localization strings.

Concerns

  • Confirm all Docker paths use the canonical dd.port.label key. The summary also reports dd.portlabel.
  • Confirm agent-host mappings refresh when the agent list changes.

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
drydock-website Ready Ready Preview Aug 8, 2026 6:52pm
drydockdemo-website Ready Ready Preview Aug 8, 2026 6:52pm

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 970f83d5-9e5d-4a69-9e02-cd38088b9fe6

📥 Commits

Reviewing files that changed from the base of the PR and between 6f728eb and beb3daa.

⛔ Files ignored due to path filters (1)
  • CHANGELOG.md is excluded by !CHANGELOG.md
📒 Files selected for processing (7)
  • ui/src/components/KeyboardShortcutsOverlay.vue
  • ui/src/components/containers/ContainerPortEntry.vue
  • ui/src/layouts/AppLayout.vue
  • ui/src/locales/en/appShell.json
  • ui/tests/components/KeyboardShortcutsOverlay.spec.ts
  • ui/tests/components/containers/ContainerPortEntry.spec.ts
  • ui/tests/layouts/AppLayout.spec.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • ui/src/components/containers/ContainerPortEntry.vue
  • ui/src/locales/en/appShell.json
  • ui/src/layouts/AppLayout.vue
  • ui/tests/components/containers/ContainerPortEntry.spec.ts

📝 Walkthrough

Walkthrough

The PR adds Docker dd.port.label support through container models, label resolution, image-detail orchestration, and documentation. The UI parses and enriches container ports, resolves agent hosts, renders published-port links, and adds an opt-in ports column. It also adds a localized keyboard-shortcuts overlay with /, ?, and Escape handling.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v1.7-ui-quickwins

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@scttbnsn

scttbnsn commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/components/containers/ContainerPortEntry.vue`:
- Around line 14-18: Update both port-label elements in the template, including
the link and non-link branches around the `container-port-link` and
`container-port-text` symbols, to add the flex min-width override alongside
`truncate` so long `dd.port.label` values can shrink and display an ellipsis
within the port row.

In `@ui/src/components/KeyboardShortcutsOverlay.vue`:
- Around line 20-34: Update KeyboardShortcutsOverlay around the dialog element
and close() to manage modal focus: store the triggering element when the overlay
opens, focus the dialog or close button after rendering, trap Tab and Shift+Tab
within the dialog, and restore the stored element’s focus when close() runs.
Keep focus constrained while visible and use the existing visibility lifecycle.

In `@ui/src/layouts/AppLayout.vue`:
- Around line 1019-1026: Update the onFocusSearch callback in
useKeyboardShortcuts to set isMobileMenuOpen to false before setting
showSearch.value to true, matching the sidebar search button behavior while
leaving onEscapeSearch unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c966ce90-3f65-4caa-b2f5-4141712ec911

📥 Commits

Reviewing files that changed from the base of the PR and between e4ef20f and 6f728eb.

⛔ Files ignored due to path filters (1)
  • CHANGELOG.md is excluded by !CHANGELOG.md
📒 Files selected for processing (41)
  • app/model/container.ts
  • app/watchers/providers/docker/Docker.containers.labels-version-finding.test.ts
  • app/watchers/providers/docker/Docker.ts
  • app/watchers/providers/docker/container-init-coverage.test.ts
  • app/watchers/providers/docker/container-init.ts
  • app/watchers/providers/docker/docker-image-details-orchestration.ts
  • app/watchers/providers/docker/label.ts
  • content/docs/current/configuration/watchers/index.mdx
  • ui/src/App.vue
  • ui/src/components/KeyboardShortcutsOverlay.vue
  • ui/src/components/containers/ContainerFullPageOverviewTab.vue
  • ui/src/components/containers/ContainerFullPageTabContent.vue
  • ui/src/components/containers/ContainerPortEntry.vue
  • ui/src/components/containers/ContainerSideTabContent.vue
  • ui/src/components/containers/ContainersGroupedViews.vue
  • ui/src/composables/useAgentHosts.ts
  • ui/src/composables/useColumnVisibility.ts
  • ui/src/composables/useKeyboardShortcuts.ts
  • ui/src/composables/useShortcutsOverlay.ts
  • ui/src/layouts/AppLayout.vue
  • ui/src/locales/en/appShell.json
  • ui/src/locales/en/containersView.json
  • ui/src/main.ts
  • ui/src/preferences/schema.ts
  • ui/src/types/container.d.ts
  • ui/src/utils/container-mapper.ts
  • ui/src/utils/ports.ts
  • ui/tests/components/ComponentImports.spec.ts
  • ui/tests/components/ContainerSideTabContent.spec.ts
  • ui/tests/components/KeyboardShortcutsOverlay.spec.ts
  • ui/tests/components/containers/ContainerFullPageOverviewTab.spec.ts
  • ui/tests/components/containers/ContainerFullPageTabContent.spec.ts
  • ui/tests/components/containers/ContainerPortEntry.spec.ts
  • ui/tests/components/containers/ContainersGroupedViews.spec.ts
  • ui/tests/composables/useAgentHosts.spec.ts
  • ui/tests/composables/useColumnVisibility.spec.ts
  • ui/tests/composables/useKeyboardShortcuts.spec.ts
  • ui/tests/composables/useShortcutsOverlay.spec.ts
  • ui/tests/layouts/AppLayout.spec.ts
  • ui/tests/utils/container-mapper.spec.ts
  • ui/tests/utils/ports.spec.ts

Comment thread ui/src/components/containers/ContainerPortEntry.vue Outdated
Comment thread ui/src/components/KeyboardShortcutsOverlay.vue
Comment thread ui/src/layouts/AppLayout.vue
Backend plumbing for a new dd.port.label Docker label: comma-separated
<port>=<label> pairs (default /tcp) that let operators attach a
friendly display name to a specific published port. Parsed alongside
the existing dd.* label overrides (table-driven, follows the
linkTemplate/displayName pattern) and passed straight through as
Container.portLabel — a raw string, consumed and matched against
individual ports client-side by the UI's clickable port links feature.
Ports:
- New ui/src/utils/ports.ts pure helpers parse the existing
  details.ports formatted strings, auto-detect http/https from the
  container-side port (443/8443 -> https), build a link target
  (bound HostIp, else an agent's resolved host via the new
  useAgentHosts() composable, else the browser's own hostname), and
  apply dd.port.label overrides.
- ContainerPortEntry.vue renders a published port as a new-tab link
  (rel=noopener noreferrer) or plain text for internal-only ports;
  wired into the side panel, both full-page detail tabs, and new
  opt-in "Ports" cells in the container table and card views.

Uptime:
- The list view's uptime cell gains a tooltip with the exact start
  timestamp; the card view now shows a live "Up ..." indicator next
  to the runtime-status badge, refreshing on the same timer as the
  table (broadened to also tick in card mode) and matching the
  full-page detail view's existing display.

Docs: dd.port.label labels-table row, a label example, and a
details.startedAt row (previously undocumented) in
content/docs/current/configuration/watchers/index.mdx.
New useKeyboardShortcuts() composable owns a single global keydown
listener: `/` focuses the search bar from anywhere (skipped when
focus is already in a text input/textarea/select/contenteditable),
`Escape` closes the search bar (in addition to each modal/panel's own
existing Escape handling), and `?` opens a new shortcut-reference
overlay (KeyboardShortcutsOverlay.vue, styled after ConfirmDialog.vue
and backed by a useShortcutsOverlay() singleton, mounted in App.vue
next to ConfirmDialog). AppLayout's local Escape-closes-search branch
is removed in favor of the composable; a `/` hint joins the existing
⌘K hint on the sidebar search button.

Also registers KeyboardShortcutsOverlay in the ComponentImports test's
global-components allowlist, and fixes a branch-coverage gap in
ports.ts (Number.isFinite overflow path) surfaced by the full-suite
run after the parallel port-links work landed.
@scttbnsn

scttbnsn commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- min-w-0 on ContainerPortEntry link/span so long dd.port.label values ellipsize instead of overflowing the flex row
- close the mobile menu before opening search in the `/` shortcut handler, matching the sidebar search button
- wire KeyboardShortcutsOverlay's dialog into the existing useFocusTrap composable: focus moves in on open, Tab/Shift+Tab trap within the dialog, focus restores to the trigger on close (guarded if it's gone)

@biggest-littlest biggest-littlest left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@scttbnsn
scttbnsn merged commit 93a2c8d into dev/v1.7 Aug 8, 2026
25 checks passed
@scttbnsn
scttbnsn deleted the feat/v1.7-ui-quickwins branch August 8, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants