DEV Community

Cover image for Replacing Cluttered Dot Dividers with Semantic Icons in GitLab's Vulnerability Report Header
Manish Kumar
Manish Kumar

Posted on Edited on

Replacing Cluttered Dot Dividers with Semantic Icons in GitLab's Vulnerability Report Header

 Small UI details can have an outsized impact on readability, especially in dense security dashboards where engineers need to scan pipeline timestamps, SBOM ingestion status, and vulnerability context analysis quickly.

In GitLab MR !269006, addressing work item #638833, I refactored the Project Vulnerability Report header to replace bullet (•) dividers with semantic icons, improve responsive wrapping and alignment, and modernize deprecated design tokens.

The result is a cleaner metadata layout that remains consistent when status items wrap across different viewport sizes.

The Problem: Why Dot Dividers Became Clutter

The relevant component was:

ee/app/assets/javascripts/security_dashboard/components/shared/project_pipeline_status.vue

It displays up to three metadata items:

  1. Security reports last updated — the latest SAST, DAST, or security pipeline information.
  2. SBOMs last updated — the latest SBOM ingestion pipeline information.
  3. Vulnerability Context Flow last updated — GitLab Duo Agent Platform context analysis information.

Previously, inline bullet characters were used as visual separators:

<div aria-hidden="true">•</div>
Enter fullscreen mode Exit fullscreen mode

These dividers were displayed at the @lg/panel breakpoint.

Following UX feedback in MR !267885, two issues became apparent.

Inconsistent wrapping: When metadata items wrapped onto multiple lines at medium or narrow viewport sizes, the standalone dots could look awkward or appear inconsistently between rows.

Inconsistent visual anchoring: The Vulnerability Context Flow component already displayed a leading tanuki-ai icon, while the Security Reports and SBOM sections had no equivalent visual anchors.

Instead of relying on punctuation between metadata blocks, each block needed a consistent visual identity.

1. Replace Dot Dividers with Semantic Icons

I replaced the standalone bullet separators with Pajamas icons that describe the content of each metadata section.

The selected icons were:

Metadata section Icon
Security reports pipeline
SBOMs package
Vulnerability Context Flow tanuki-ai

The Security Reports section now uses a leading pipeline icon:

<span class="gl-mr-3 gl-inline-flex gl-shrink-0 gl-items-center gl-font-bold">
  <gl-icon name="pipeline" class="gl-mr-2" />
  {{ $options.i18n.lastUpdated }}
</span>
Enter fullscreen mode Exit fullscreen mode

The SBOM section follows the same pattern:

<span class="gl-mr-3 gl-inline-flex gl-shrink-0 gl-items-center gl-font-bold">
  <gl-icon name="package" class="gl-mr-2" />
  {{ $options.i18n.sbomLastUpdated }}
</span>
Enter fullscreen mode Exit fullscreen mode

The Vulnerability Context Flow section continues to use its existing tanuki-ai icon inside vulnerability_context_flow_last_run.vue.

This gives each metadata block its own visual anchor. When the layout wraps, the icons remain associated with their respective labels instead of leaving standalone punctuation between rows.

2. Improve Flex Spacing and Vertical Alignment

Removing the dividers also meant the layout needed a consistent spacing strategy.

I added gl-gap-x-6 to the outer flex container:

<div class="gl-border-b gl-flex-wrap gl-gap-x-6 gl-gap-y-4 gl-bg-subtle gl-p-5 @lg/panel:gl-flex">
Enter fullscreen mode Exit fullscreen mode

This provides a consistent 24px horizontal gap between metadata sections, while gl-gap-y-4 controls vertical spacing when items wrap.

During review, Fiona McCawley identified a subtle vertical alignment mismatch in the SBOM block.

The Security Reports section used a flex-based structure with:

  • gl-flex
  • gl-flex-wrap
  • gl-items-center
  • gl-gap-y-2

Its timestamp, pipeline link, and badge wrapper also used:

  • gl-flex
  • gl-items-center
  • gl-whitespace-nowrap

The SBOM block did not have the same structure.

I aligned the SBOM markup with the Security Reports block so that its package icon, bold label, relative timestamp, pipeline link, and status badge line up consistently.

I also removed a redundant gl-mr-3 from the SBOM parsing status notice. This keeps the spacing before VulnerabilityContextFlowLastRun consistent with the 24px horizontal gap.

3. Remove Dead Code and Modernize Design Tokens

While updating the layout, I also cleaned up two related areas.

Remove the unused prepend slot

The component:

ee/app/assets/javascripts/vulnerabilities/components/vulnerability_context_flow_last_run.vue

contained:

<slot name="prepend" />
Enter fullscreen mode Exit fullscreen mode

The slot had been used to inject the bullet divider from project_pipeline_status.vue.

Once the divider was removed, the slot no longer had a purpose. After checking that there were no remaining consumers, I removed it.

This eliminates unused template code and simplifies the component interface.

Replace the deprecated orange text token

Danger Bot flagged gl-text-orange-400 as a deprecated design token.

I replaced it with the semantic token:

gl-text-warning
Enter fullscreen mode Exit fullscreen mode

The update applied to both parsing status notices:

  • parsingStatusMessage
  • sbomParsingStatusMessage

Using a semantic warning token communicates the intended meaning rather than depending on a specific color shade.

It also keeps the implementation aligned with the design system's token conventions.

4. Update Jest Specs

The corresponding tests were in:

ee/spec/frontend/security_dashboard/components/shared/project_pipeline_status_spec.js

Since the standalone divider elements were removed, I deleted the assertions that depended on the pipeline-divider data-testid.

I added targeted tests to verify that the correct icons render in their respective sections:

it('should show the pipeline icon', () => {
  expect(findPipelineIcon().props('name')).toBe('pipeline');
});

it('should show the package icon', () => {
  expect(findSbomPipelineIcon().props('name')).toBe('package');
});
Enter fullscreen mode Exit fullscreen mode

These assertions verify that the Security Reports section uses the pipeline icon and the SBOM section uses the package icon.

The tests focus on the new component behavior rather than the implementation details of the removed divider elements.

5. What the Review Process Taught Me

This MR also highlighted a few practical frontend engineering lessons.

Check responsive layouts at multiple widths. Container-query breakpoints such as @md/panel and @lg/panel can produce different wrapping behavior. Reviewing both wide and narrow screenshots helps catch visual problems that may not be obvious from the markup alone.

Keep sibling components structurally consistent. Matching flex alignment, wrapping, and whitespace classes helps prevent subtle baseline differences between metadata sections.

Prefer semantic icons over punctuation separators. Icons provide context about the information being displayed and remain attached to their content when the layout changes.

Remove obsolete interfaces after removing their consumers. Deleting the unused prepend slot prevents unnecessary component API surface from accumulating.

Use semantic design tokens. Replacing deprecated color-specific classes with semantic tokens makes the intent of the UI clearer and keeps styling aligned with the design system.

Conclusion

The Vulnerability Report header refactor was more than a visual cleanup.

Replacing standalone bullet dividers with semantic icons improved the structure of the metadata sections. Consistent flex spacing and alignment made responsive wrapping cleaner, while removing the unused slot and replacing deprecated design tokens improved maintainability.

The accompanying Jest updates ensure that the new pipeline and package icons are rendered in the correct sections.

This work is a reminder that good frontend engineering is not only about adding features. It also involves making small interface details predictable, accessible, consistent, and easier to maintain.

References

Thanks to @fmccawley and @lorenzvanherwaarden for the review and merge!


Author: Manish Kumar

GitLab: @manishpatel00

Top comments (0)