Workplace Image SEQIS Group GmbH

Improving Merge Reviews

Description

Timo Keber von SEQIS zeigt in seinem devjobs.at TechTalk die maßgeschneiderten Lösungen, die das Team für die Merge Reviews mit GitLab in VS Code verwendet.

By playing the video, you agree to data transfer to YouTube and acknowledge the privacy policy.

Video Summary

In Improving Merge Reviews, Timo Keber shows how he’s adding Draft Notes and batch reviews to the GitLab VS Code Extension to prevent notification spam from single comments and achieve feature parity with the web UI. He details the architecture using TypeScript, VS Code WebViews, and an Issueable Controller bridging to the GitLab API, and the main hurdles: a split API (GraphQL for regular comments vs REST for draft notes) and tightly coupled GraphQL-centric code. A live demo covers initial progress (a Start Review button, creating draft notes via REST and submitting them through a command) and techniques like bidirectional WebView–extension messaging and a local persistence approach that developers can apply to similar tooling.

Taming Merge Review Noise: Bringing Draft Notes to the GitLab VS Code Extension

Session context: “Improving Merge Reviews” by Timo Keber (SEQIS Group GmbH)

In “Improving Merge Reviews,” Timo Keber (SEQIS Group GmbH) tackles a deceptively simple gap with big day-to-day consequences: the GitLab VS Code Extension doesn’t support Draft Notes and Batch Reviews the way the GitLab web UI does. For teams who prefer to review merge requests inside the editor, that missing feature creates context switching, notification overload, and friction in what should be a tight feedback loop.

We watched the session because it shows, in a very practical way, how open-source contributions evolve inside complex product ecosystems. Keber walks through why Draft Notes matter, how the extension is structured, where API boundaries get in the way, and what he has working already. The goal is straightforward: reach feature parity with the web UI so the MR review flow in VS Code matches what people rely on in the browser.

Core idea: collect unpublished review comments as drafts, then publish them all at once—instead of sending one notification per comment.

Why Draft Notes in the IDE matter

If you use GitLab in the browser, the behavior is familiar: you can draft comments during a review and publish them in one batch at the end. That improves three things:

  • Focus: you stay in the review flow without constantly switching modes.
  • Signal over noise: one consolidated review notification rather than a trickle of pings.
  • Quality: you see the whole picture before finalizing comments, which avoids inconsistent feedback.

The GitLab VS Code Extension, however, currently publishes each comment immediately, which means one email/notification per comment. Keber highlights two immediate consequences:

  • Notification overload—the “ping hell” that nudges people to mute notifications altogether.
  • Forced context switching: to get drafting and batching, reviewers have to leave VS Code and go back to the web UI.

In our view, this is a textbook case of “feature parity equals developer experience.” If the editor workflow deviates on critical review actions, people pay for it with attention and time.

Architecture in brief: how the GitLab VS Code Extension is put together

Keber’s architectural overview lands four key components:

1) Extension host and TypeScript code

  • The extension is written in TypeScript and hooks into both the VS Code API and the GitLab API.
  • The extension host provides the debugging/runtime environment during development.

2) WebViews (using Vue)

  • UI like the merge request view is rendered in a WebView.
  • The extension uses Vue to style and manage the WebView.

3) Issuable controllers

  • GitLab treats a Merge Request as an “Issuable.” The extension provides Issuable Controllers for that abstraction.
  • These controllers handle communication between the WebView and extension code, and they publish to the GitLab API.

4) GitLab service and API layer

  • The GitLab service is responsible for API calls to GitLab.
  • Today, comments in the extension are strongly aligned to GraphQL. Draft Notes in GitLab, however, are served via a separate REST endpoint.

That last point sets up the central architectural challenge Keber tackles: the extension has to structure WebView interactions and local state so that GraphQL-based comments and REST-based draft notes can be created, displayed, and reconciled consistently.

The core friction: GraphQL vs. REST

As so often, the complexity isn’t in the UI—but in the data and API flows behind it. Keber points to two sticking points:

  • Different APIs: “Regular” comments are handled over GraphQL; Draft Notes use REST. Fields, mutations, and return shapes don’t overlap neatly.
  • Tight coupling in the current code: the extension’s comment handling is built around GraphQL nodes. There’s no clean separation that would let REST-based drafts slot in easily.

He illustrates this with the CreateNode path in the GitLab service: it’s filled with GraphQL-specific logic—old vs. new mutations, result checks, GraphQL-shaped objects. Draft Notes, by contrast, go to a REST endpoint with a simple body. While that sounds straightforward, it doesn’t fit the extension’s current assumptions. What’s needed is an internal bridge that unifies both pathways for the WebView.

Paraphrase: “GraphQL for comments, REST for Draft Notes—clean in theory, awkward in the extension’s implementation. We need to bridge the two.”

Communication flow: WebView ↔ Extension ↔ GitLab

Drafting is not just a “send this” problem. Keber moves the extension toward truly bidirectional communication:

  • WebView → Extension: user actions (e.g., start a review, add a draft note) are posted to the Issuable Controller.
  • Extension → WebView: the controller pushes updated state back to the WebView. Keber injects feature flags into the HTML so the WebView knows the current context and renders accordingly.

Bidirectional updates are essential because drafting is also a visibility and state problem: reviewers need to see which comments are drafts, which are published, and what’s queued for publishing. Without reliable back-and-forth, the UI drifts out of sync.

State persistence: keeping drafts safe locally

Keber proposes a state persistence layer to store unpublished Draft Notes locally. In a VS Code extension, that matters for two reasons:

  • Prevent data loss: restarts, reloads, or transient network issues shouldn’t nuke your draft review.
  • Enable batching: the “basket” of review comments needs to survive context switches so you can publish them together.

In the current demo phase, this is an idea rather than a fully wired subsystem, but its role is clear: without a resilient draft store, batch reviews become brittle.

UX and maintainer feedback: slow down to get it right

Keber notes that maintainers provided quick, helpful feedback—and applied the brakes a bit around UX reviews. That’s typical for product-adjacent open source. An extension used daily across teams can’t ship half-baked UX. The direction is right—Draft Notes and Batch Reviews address a real need—but the implementation must be consistent and durable.

For contributors, the lesson is familiar: stabilize architecture and API design first, then refine the UI. That’s the approach Keber is taking.

The demo: “Start Review” and posting Draft Notes from VS Code

In the live part, Keber runs both a live build and the extension host (debug session). Two highlights stood out:

  • A new “Start Review” button: intentionally simple, mirroring the web UI to toggle into review drafting mode.
  • Posting draft notes: the WebView posts a message to the Issuable Controller, which calls the REST endpoint for Draft Notes.

What works today:

  • Regular comments via the GraphQL path, as before.
  • Creating Draft Notes once “Start Review” is active.
  • Submitting Draft Notes—currently via a VS Code command rather than a dedicated UI button.

What’s still missing:

  • A clear visual distinction for drafts vs. published comments in the extension’s MR view.
  • Full draft CRUD (Keber mentions “CRUD without D,” and update is not in place yet).
  • A polished publish flow in the UI (not just a command).

Direct quote in essence: “Baby steps.” Small, working increments, not a big bang that puts the core logic at risk.

Technical focus areas

1) Type unions for REST and GraphQL nodes

Keber’s direction is to unify REST Draft Notes and GraphQL comments under a single type union. That lets the WebView treat comments consistently while the controller handles the API-specific details.

  • Upside: simpler UI/view logic; API source becomes an implementation detail.
  • Challenge: mapping fields, IDs, status (draft vs. published), and transitions (publish) cleanly.

2) Feature flags in the WebView

To keep the WebView context-aware, Keber injects feature flags into the HTML so the Vue frontend knows whether drafting is active in the current MR and which actions are allowed.

  • Upside: fewer hard couplings to extension internals; declarative switches.
  • Challenge: keep flags in sync on MR changes and WebView refresh.

3) A bridging layer in the GitLab service

The existing CreateNode flow is GraphQL-heavy. Drafts add a REST pathway on top. That implies:

  • Two plumbing routes: REST for drafts, GraphQL for regular comments.
  • Unified error handling: both paths must report success/failure consistently and update UI state accordingly.
  • Forward compatibility: if GitLab evolves (e.g., Draft Notes over GraphQL someday), the abstraction should accommodate the change.

4) True bidirectional events between WebView and extension

The WebView can’t just fire-and-forget; it needs to receive new state: which drafts exist, what’s been published, any server feedback. Without that, the UI desynchronizes.

  • Typical events: draft created, draft saved, draft published, publish error, refresh required.
  • Implementation hint: a concise, documented message contract reduces coupling and improves testability.

The “ping hell” in practice

Keber puts it plainly: if every comment from the IDE triggers a notification, then reviewers and authors drown in noise. The predictable outcomes are familiar:

  • People lose track of what’s important.
  • Teams mute notifications, and critical items get missed or delayed.
  • The review flow turns into a staccato of microevents rather than a coherent feedback package.

Draft Notes and batch publishing aren’t “nice-to-haves”—they’re a guardrail for attention and review quality.

What we took away: lessons for engineers

Beyond the specifics of GitLab, several general lessons stand out:

  • Feature parity isn’t window dressing: if you’re offering IDE workflows, match the critical UX paths of the web UI. Otherwise, you force context switching.
  • Address API duality early: when similar entities live behind different APIs (GraphQL vs. REST), build a stable internal abstraction before the UI proliferates.
  • Design for bidirectional updates: VS Code WebViews are real frontends. Without clear event/state channels, you’ll get ghost states and inconsistent UIs.
  • Plan for local persistence: drafting without a reliable local store is risky; persistence is part of the core design for batch operations.

What’s next before true parity

Keber openly lists what needs to happen before the extension feels “draft-ready” end to end:

  • Visual distinction in the MR view: drafts must be recognizable, ideally following the web UI’s visual cues.
  • Full draft CRUD: not just create, but also update and delete—plus robust error handling.
  • A first-class publish flow in the UI: a visible button and a clear state transition (pending → published), not only a VS Code command.
  • Establish the type union: a clear, end-to-end comment model that the extension can consistently rely on.

Once these are in place, teams who prefer reviewing in VS Code will get a much smoother experience—especially those who want to avoid the browser for day-to-day reviewing.

The developer reality: breakpoints and iteration

Keber’s live run also shows the reality of building extensions: breakpoints triggering mid-demo, a command that doesn’t fire at first—nothing unusual, but a reminder that this is real, ongoing work. The direction is solid, and the milestones are within reach.

Conclusion: a small bridge with big impact

“Improving Merge Reviews” by Timo Keber (SEQIS Group GmbH) makes a strong case that Draft Notes aren’t cosmetic; they’re leverage against notification overload and for higher-quality reviews. The technical challenge—bridging GraphQL and REST, wiring bidirectional messages, and adding a resilient local draft store—is real. But the payoff justifies the effort.

Three points stick with us:

  • Reviews belong where development happens—in the IDE.
  • Feature parity is a quality promise, not marketing.
  • Iterative delivery, early maintainer feedback, and clean abstractions are the ingredients for extending complex tools safely.

Practical takeaways for your work

  • Treat the WebView as a proper frontend with a clear messaging contract. That’s how you achieve true bidirectionality.
  • Build an internal type union if you need to unify entities from different APIs. Decouple UI from API specifics.
  • Add local draft persistence whenever users need to “park” entities before committing them. It prevents data loss and enables robust batch operations.
  • Make batch actions visible and trustworthy: a clear publish button is more than convenience—it’s a UX anchor.
  • Seek UX feedback early, especially for tools people use every day. Patience in polish pays dividends.

Outlook

With the first building blocks in place—“Start Review,” posting Draft Notes over REST, and a command-driven publish path—the path to parity is visible. Once visual distinction, full CRUD, and a polished publish UI land, the GitLab VS Code Extension will deliver a calmer, more coherent review rhythm. That’s precisely what productive teams need: fewer pings, more focus, and better merge reviews right inside VS Code.

More Tech Talks

More Tech Lead Stories

More Dev Stories