Skip to content

feat: add Docker Desktop Logs view hints and navigation shortcut#13721

Merged
glours merged 1 commit intomainfrom
feat/logs-desktop-hint
Apr 10, 2026
Merged

feat: add Docker Desktop Logs view hints and navigation shortcut#13721
glours merged 1 commit intomainfrom
feat/logs-desktop-hint

Conversation

@glours
Copy link
Copy Markdown
Contributor

@glours glours commented Apr 8, 2026

What I did

  • Add CLI hooks handler to show "What's next:" hints pointing to the Docker Desktop Logs view after docker logs, docker compose logs, and docker compose up -d.

  • Add l keyboard shortcut in the compose up navigation menu to open the Logs view, gated on Docker Desktop feature flag and settings.

Related issue
N/A

(not mandatory) A picture of a cute animal, if possible in relation to what you did
image

@glours glours force-pushed the feat/logs-desktop-hint branch 2 times, most recently from a7d9937 to 3db809c Compare April 9, 2026 12:03
@glours glours self-assigned this Apr 10, 2026
@glours glours marked this pull request as ready for review April 10, 2026 05:43
@glours glours requested a review from a team as a code owner April 10, 2026 05:43
@glours glours requested review from Copilot and ndeloof April 10, 2026 05:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Docker Desktop “Logs view” discoverability to Docker Compose by emitting “What’s next” hints via Docker CLI hooks and by introducing an l keyboard shortcut in the compose up navigation menu (gated by Desktop feature flag + user setting).

Changes:

  • Introduce a hidden hooks subcommand that returns “Next steps” templates for docker logs, docker compose logs, and docker compose up -d.
  • Add Logs-view keyboard shortcut (l) to the compose up navigation menu when the Desktop LogsTab feature is enabled.
  • Extend Desktop client integration to check feature flags and Desktop settings (incl. backend socket derivation) and record tracing metrics for availability.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pkg/compose/up.go Computes Desktop/LogsTab availability to gate nav menu behavior + tracing.
pkg/compose/desktop.go Refactors Desktop endpoint detection and adds “feature enabled” helper.
internal/tracing/keyboard_metrics.go Adds logs-view availability to nav menu metrics attributes.
internal/desktop/client.go Adds feature+settings checks and backend socket endpoint derivation.
internal/desktop/client_test.go Adds unit coverage for backend socket endpoint derivation.
cmd/main.go Registers the new hooks subcommand on the root command.
cmd/formatter/shortcut.go Adds l shortcut + handler to open Docker Desktop Logs view.
cmd/compose/hooks.go Implements hidden hooks handler that returns “What’s next” hints.
cmd/compose/hooks_test.go Adds tests for hook request parsing and hint gating.
cmd/compose/compose.go Updates standalone detection to account for hook subcommand.
Comments suppressed due to low confidence (1)

cmd/main.go:51

  • The hook subcommand will still trigger the parent (compose) PersistentPreRunE defined below, so plugin initialization (plugin.PersistentPreRunE/cmdtrace setup) will still run on hook invocations. Overriding PersistentPreRunE on the hook command does not prevent the parent persistent pre-run in Cobra. Consider short-circuiting this wrapper when cmd.Name() == metadata.HookSubcommandName (or similar) so hook execution is fast and does not depend on Docker/CLI initialization.
			cmd := commands.RootCommand(cli, backendOptions)
			cmd.AddCommand(commands.HooksCommand())
			originalPreRunE := cmd.PersistentPreRunE
			cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
				// initialize the cli instance
				if err := plugin.PersistentPreRunE(cmd, args); err != nil {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +64 to +70
func HooksCommand() *cobra.Command {
return &cobra.Command{
Use: metadata.HookSubcommandName,
Hidden: true,
// Override PersistentPreRunE to prevent the parent's PersistentPreRunE
// (plugin initialization) from running for hook invocations.
PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This comment and the no-op PersistentPreRunE won’t actually prevent the parent command’s PersistentPreRunE from running (Cobra runs parent persistent pre-runs before the subcommand’s). To avoid plugin initialization for hooks, add the gating in the parent PersistentPreRunE (e.g., in cmd/main.go wrapper) or restructure command setup; otherwise hooks will still pay the full init cost.

Suggested change
func HooksCommand() *cobra.Command {
return &cobra.Command{
Use: metadata.HookSubcommandName,
Hidden: true,
// Override PersistentPreRunE to prevent the parent's PersistentPreRunE
// (plugin initialization) from running for hook invocations.
PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
//
// Note: a child command's PersistentPreRunE does not prevent a parent's
// PersistentPreRunE from running in Cobra. Any optimization to skip parent
// plugin initialization for hook invocations must be implemented where the
// parent command is configured.
func HooksCommand() *cobra.Command {
return &cobra.Command{
Use: metadata.HookSubcommandName,
Hidden: true,

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +186
// Settings fetches the Docker Desktop application settings.
func (c *Client) Settings(ctx context.Context) (*SettingsResponse, error) {
req, err := c.newRequest(ctx, http.MethodGet, "/app/settings", http.NoBody)
if err != nil {
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}

var ret SettingsResponse
if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

// IsFeatureEnabled checks both the feature flag (GET /features) and the user
// setting (GET /app/settings) for a given feature. Returns true only when the
// feature is both rolled out and enabled by the user. Features without a
// corresponding setting entry are considered enabled if the flag is set.
func (c *Client) IsFeatureEnabled(ctx context.Context, feature string) (bool, error) {
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

New Settings() and IsFeatureEnabled() logic (feature flag + per-feature settings check, including backendSocketEndpoint derivation) is not covered by tests in this package. Consider adding unit tests that stub the HTTP client/transport (and ideally the backend client creation) to verify: feature absent/disabled, feature enabled with no setting check, and FeatureLogsTab enabled with settings true/false.

Copilot uses AI. Check for mistakes.
Add CLI hooks handler to show "What's next:" hints pointing to the
Docker Desktop Logs view after `docker logs`, `docker compose logs`,
and `docker compose up -d`.

Add `l` keyboard shortcut in the `compose up` navigation menu to
open the Logs view, gated on Docker Desktop feature flag and settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
@glours glours force-pushed the feat/logs-desktop-hint branch from 3db809c to ed28998 Compare April 10, 2026 06:03
// hooksHints maps hook root commands to their hint definitions.
var hooksHints = map[string]hookHint{
// standalone "docker logs" (not a compose subcommand)
"logs": {template: dockerLogsHint},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unclear to me why we provide docker logs hint inside compose. Maybe just because we have no place in docker/cli for this and compose used to be installed by 99% users?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's because Compose is in charge of this hint globally, it could trigger the hint display to any other cli plugins too.

@glours glours merged commit 182defa into main Apr 10, 2026
50 checks passed
@glours glours deleted the feat/logs-desktop-hint branch April 10, 2026 13:26
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.

3 participants