[gnome-builder] plugins/buildui: port to GTK 4



commit 37a6e0988bf1a16aa377dab377c9f24175b23add
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jul 11 22:28:50 2022 -0700

    plugins/buildui: port to GTK 4
    
    First, this still needs a bit of work around how we configure projects.
    That is still unfinished like a lot of this port so far.
    
     - New runnables dialog
     - New build targets dialog
     - New preferences integration
     - New status popover in the statusbar
     - New keybindings
     - Remove config surface
     - Remove libdazzle usage

 src/plugins/buildui/buildui-plugin.c               |   8 +-
 src/plugins/buildui/buildui.gresource.xml          |   8 +-
 src/plugins/buildui/buildui.plugin                 |   3 +-
 src/plugins/buildui/gbp-buildui-config-surface.c   | 343 ---------------
 src/plugins/buildui/gbp-buildui-config-surface.ui  |  28 --
 .../buildui/gbp-buildui-editor-page-addin.c        |  14 +-
 src/plugins/buildui/gbp-buildui-log-pane.c         | 120 +++---
 src/plugins/buildui/gbp-buildui-log-pane.h         |   1 -
 src/plugins/buildui/gbp-buildui-log-pane.ui        |  28 +-
 src/plugins/buildui/gbp-buildui-omni-bar-section.c |  55 ++-
 src/plugins/buildui/gbp-buildui-omni-bar-section.h |   4 +-
 .../buildui/gbp-buildui-omni-bar-section.ui        | 396 +++--------------
 src/plugins/buildui/gbp-buildui-pane.c             | 413 ++----------------
 src/plugins/buildui/gbp-buildui-pane.h             |   4 +-
 src/plugins/buildui/gbp-buildui-pane.ui            | 148 ++-----
 .../buildui/gbp-buildui-preferences-addin.c        | 474 +++++++++++++++++++++
 .../buildui/gbp-buildui-preferences-addin.h        |  31 ++
 src/plugins/buildui/gbp-buildui-runnables-dialog.c | 315 ++++++++++++++
 ...ig-surface.h => gbp-buildui-runnables-dialog.h} |  14 +-
 .../buildui/gbp-buildui-runnables-dialog.ui        | 101 +++++
 .../buildui/gbp-buildui-runtime-categories.c       |  22 +-
 src/plugins/buildui/gbp-buildui-runtime-row.c      |  37 +-
 src/plugins/buildui/gbp-buildui-runtime-row.h      |   4 +-
 src/plugins/buildui/gbp-buildui-stage-row.c        |  44 +-
 src/plugins/buildui/gbp-buildui-stage-row.ui       |   8 +-
 src/plugins/buildui/gbp-buildui-status-indicator.c | 104 +++++
 src/plugins/buildui/gbp-buildui-status-indicator.h |  35 ++
 .../buildui/gbp-buildui-status-indicator.ui        |  48 +++
 .../buildui/gbp-buildui-status-popover-row.ui      |  45 ++
 src/plugins/buildui/gbp-buildui-status-popover.c   | 321 ++++++++++++++
 src/plugins/buildui/gbp-buildui-status-popover.h   |  37 ++
 src/plugins/buildui/gbp-buildui-status-popover.ui  | 112 +++++
 src/plugins/buildui/gbp-buildui-targets-dialog.c   | 251 +++++++++++
 src/plugins/buildui/gbp-buildui-targets-dialog.h   |  35 ++
 src/plugins/buildui/gbp-buildui-targets-dialog.ui  |  57 +++
 src/plugins/buildui/gbp-buildui-tree-addin.c       |  86 ++--
 src/plugins/buildui/gbp-buildui-workspace-addin.c  | 278 ++++++------
 src/plugins/buildui/gtk/keybindings.json           |  11 +
 src/plugins/buildui/gtk/menus.ui                   | 161 ++++++-
 src/plugins/buildui/meson.build                    |   8 +-
 src/plugins/buildui/themes/shared.css              |   9 -
 41 files changed, 2604 insertions(+), 1617 deletions(-)
---
diff --git a/src/plugins/buildui/buildui-plugin.c b/src/plugins/buildui/buildui-plugin.c
index ed8059117..4930e1933 100644
--- a/src/plugins/buildui/buildui-plugin.c
+++ b/src/plugins/buildui/buildui-plugin.c
@@ -27,20 +27,26 @@
 #include <libide-gui.h>
 #include <libide-tree.h>
 
-#include "gbp-buildui-config-view-addin.h"
+//#include "gbp-buildui-config-view-addin.h"
 #include "gbp-buildui-editor-page-addin.h"
+#include "gbp-buildui-preferences-addin.h"
 #include "gbp-buildui-workspace-addin.h"
 #include "gbp-buildui-tree-addin.h"
 
 _IDE_EXTERN void
 _gbp_buildui_register_types (PeasObjectModule *module)
 {
+#if 0
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_CONFIG_VIEW_ADDIN,
                                               GBP_TYPE_BUILDUI_CONFIG_VIEW_ADDIN);
+#endif
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_EDITOR_PAGE_ADDIN,
                                               GBP_TYPE_BUILDUI_EDITOR_PAGE_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_PREFERENCES_ADDIN,
+                                              GBP_TYPE_BUILDUI_PREFERENCES_ADDIN);
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_WORKSPACE_ADDIN,
                                               GBP_TYPE_BUILDUI_WORKSPACE_ADDIN);
diff --git a/src/plugins/buildui/buildui.gresource.xml b/src/plugins/buildui/buildui.gresource.xml
index 71dc36377..8eb6d16ee 100644
--- a/src/plugins/buildui/buildui.gresource.xml
+++ b/src/plugins/buildui/buildui.gresource.xml
@@ -2,12 +2,16 @@
 <gresources>
   <gresource prefix="/plugins/buildui">
     <file>buildui.plugin</file>
-    <file preprocess="xml-stripblanks">gbp-buildui-config-surface.ui</file>
+    <file>gtk/keybindings.json</file>
     <file preprocess="xml-stripblanks">gbp-buildui-log-pane.ui</file>
     <file preprocess="xml-stripblanks">gbp-buildui-omni-bar-section.ui</file>
     <file preprocess="xml-stripblanks">gbp-buildui-pane.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-runnables-dialog.ui</file>
     <file preprocess="xml-stripblanks">gbp-buildui-stage-row.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-status-indicator.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-status-popover.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-status-popover-row.ui</file>
+    <file preprocess="xml-stripblanks">gbp-buildui-targets-dialog.ui</file>
     <file preprocess="xml-stripblanks">gtk/menus.ui</file>
-    <file>themes/shared.css</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/buildui/buildui.plugin b/src/plugins/buildui/buildui.plugin
index e5b4cc3a7..5864fdb10 100644
--- a/src/plugins/buildui/buildui.plugin
+++ b/src/plugins/buildui/buildui.plugin
@@ -2,10 +2,11 @@
 Authors=Christian Hergert <christian hergert me>
 Builtin=true
 Copyright=Copyright © 2015-2018 Christian Hergert
-Depends=editor;project-tree;
+Depends=project-tree;
 Description=Provides user interface components to display the build settings.
 Embedded=_gbp_buildui_register_types
 Hidden=true
 Module=buildui
 Name=Build user interface components
 X-Workspace-Kind=primary;
+X-Preferences-Kind=project;
\ No newline at end of file
diff --git a/src/plugins/buildui/gbp-buildui-editor-page-addin.c 
b/src/plugins/buildui/gbp-buildui-editor-page-addin.c
index 427f3e9a0..aabbdef3a 100644
--- a/src/plugins/buildui/gbp-buildui-editor-page-addin.c
+++ b/src/plugins/buildui/gbp-buildui-editor-page-addin.c
@@ -63,16 +63,17 @@ parse_version (const gchar *str,
 
 static void
 on_push_snippet_cb (GbpBuilduiEditorPageAddin *self,
-                    IdeSnippet                *snippet,
-                    const GtkTextIter         *iter,
+                    GtkSourceSnippet          *snippet,
+                    GtkTextIter               *iter,
                     IdeSourceView             *view)
 {
   g_autoptr(IdeContext) context = NULL;
   g_autofree gchar *project_version = NULL;
+  GtkSourceSnippetContext *snippet_context;
   GtkTextBuffer *buffer;
 
   g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (IDE_IS_SNIPPET (snippet));
+  g_assert (GTK_SOURCE_IS_SNIPPET (snippet));
   g_assert (IDE_IS_SOURCE_VIEW (view));
 
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
@@ -105,9 +106,10 @@ on_push_snippet_cb (GbpBuilduiEditorPageAddin *self,
         }
     }
 
-  ide_snippet_context_add_variable (ide_snippet_get_context (snippet),
-                                    "project_version",
-                                    project_version ?: "");
+  snippet_context = gtk_source_snippet_get_context (snippet);
+  gtk_source_snippet_context_set_variable (snippet_context,
+                                           "project_version",
+                                           project_version ?: "");
 }
 
 static void
diff --git a/src/plugins/buildui/gbp-buildui-log-pane.c b/src/plugins/buildui/gbp-buildui-log-pane.c
index 71db6ac04..22f9ade55 100644
--- a/src/plugins/buildui/gbp-buildui-log-pane.c
+++ b/src/plugins/buildui/gbp-buildui-log-pane.c
@@ -152,7 +152,7 @@ gbp_buildui_log_pane_window_title_changed (GbpBuilduiLogPane *self,
     }
 }
 
-static void
+static gboolean
 gbp_buildui_log_pane_grab_focus (GtkWidget *widget)
 {
   GbpBuilduiLogPane *self = (GbpBuilduiLogPane *)widget;
@@ -160,7 +160,9 @@ gbp_buildui_log_pane_grab_focus (GtkWidget *widget)
   g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
 
   if (self->terminal != NULL)
-    gtk_widget_grab_focus (GTK_WIDGET (self->terminal));
+    return gtk_widget_grab_focus (GTK_WIDGET (self->terminal));
+
+  return FALSE;
 }
 
 static void
@@ -261,6 +263,49 @@ gbp_buildui_log_pane_clear_activate (GSimpleAction *action,
   gbp_buildui_log_pane_reset_view (self);
 }
 
+static void
+gbp_builui_log_pane_save_response (GtkFileChooserNative *native,
+                                   int                   response,
+                                   GbpBuilduiLogPane    *self)
+{
+  g_autoptr(GFile) file = NULL;
+
+  IDE_ENTRY;
+
+  if (response != GTK_RESPONSE_ACCEPT)
+    IDE_RETURN ();
+
+  file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
+
+  if (file != NULL)
+    {
+      g_autoptr(GFileOutputStream) stream = NULL;
+      g_autoptr(GError) error = NULL;
+
+      stream = g_file_replace (file,
+                               NULL,
+                               FALSE,
+                               G_FILE_CREATE_REPLACE_DESTINATION,
+                               NULL,
+                               &error);
+
+      if (stream != NULL)
+        {
+          vte_terminal_write_contents_sync (VTE_TERMINAL (self->terminal),
+                                            G_OUTPUT_STREAM (stream),
+                                            VTE_WRITE_DEFAULT,
+                                            NULL,
+                                            &error);
+          g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
+        }
+
+      if (error != NULL)
+        g_warning ("Failed to write contents: %s", error->message);
+    }
+
+  IDE_EXIT;
+}
+
 static void
 gbp_buildui_log_pane_save_in_file (GSimpleAction *action,
                                    GVariant      *param,
@@ -269,7 +314,6 @@ gbp_buildui_log_pane_save_in_file (GSimpleAction *action,
   GbpBuilduiLogPane *self = user_data;
   g_autoptr(GtkFileChooserNative) native = NULL;
   GtkWidget *window;
-  gint res;
 
   IDE_ENTRY;
 
@@ -283,66 +327,16 @@ gbp_buildui_log_pane_save_in_file (GSimpleAction *action,
                                         _("_Save"),
                                         _("_Cancel"));
 
-  res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
+  g_signal_connect (native,
+                    "response",
+                    G_CALLBACK (gbp_builui_log_pane_save_response),
+                    self);
 
-  if (res == GTK_RESPONSE_ACCEPT)
-    {
-      g_autoptr(GFile) file = NULL;
-
-      file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
-
-      if (file != NULL)
-        {
-          g_autoptr(GFileOutputStream) stream = NULL;
-          g_autoptr(GError) error = NULL;
-
-          stream = g_file_replace (file,
-                                   NULL,
-                                   FALSE,
-                                   G_FILE_CREATE_REPLACE_DESTINATION,
-                                   NULL,
-                                   &error);
-
-          if (stream != NULL)
-            {
-              vte_terminal_write_contents_sync (VTE_TERMINAL (self->terminal),
-                                                G_OUTPUT_STREAM (stream),
-                                                VTE_WRITE_DEFAULT,
-                                                NULL,
-                                                &error);
-              g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL);
-            }
-
-          if (error != NULL)
-            g_warning ("Failed to write contents: %s", error->message);
-        }
-    }
+  gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
 
   IDE_EXIT;
 }
 
-static void
-terminal_size_allocate (GbpBuilduiLogPane *self,
-                        GtkAllocation     *allocation,
-                        IdeTerminal       *terminal)
-{
-  VtePty *pty;
-  gint rows = 0;
-  gint columns = 0;
-
-  g_assert (GBP_IS_BUILDUI_LOG_PANE (self));
-  g_assert (allocation != NULL);
-  g_assert (IDE_IS_TERMINAL (terminal));
-
-  pty = vte_terminal_get_pty (VTE_TERMINAL (self->terminal));
-
-  if (self->pipeline != NULL && pty != NULL)
-    {
-      if (vte_pty_get_size (pty, &rows, &columns, NULL))
-        _ide_pipeline_set_pty_size (self->pipeline, rows, columns);
-    }
-}
-
 static void
 gbp_buildui_log_pane_init (GbpBuilduiLogPane *self)
 {
@@ -354,13 +348,7 @@ gbp_buildui_log_pane_init (GbpBuilduiLogPane *self)
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  dzl_dock_widget_set_icon_name (DZL_DOCK_WIDGET (self), "builder-build-info-symbolic");
-
-  g_signal_connect_object (self->terminal,
-                           "size-allocate",
-                           G_CALLBACK (terminal_size_allocate),
-                           self,
-                           G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+  panel_widget_set_icon_name (PANEL_WIDGET (self), "builder-build-info-symbolic");
 
   g_signal_connect_object (self->terminal,
                            "window-title-changed",
@@ -368,7 +356,7 @@ gbp_buildui_log_pane_init (GbpBuilduiLogPane *self)
                            self,
                            G_CONNECT_SWAPPED);
 
-  dzl_dock_widget_set_title (DZL_DOCK_WIDGET (self), _("Build Output"));
+  panel_widget_set_title (PANEL_WIDGET (self), _("Build Output"));
 
   gbp_buildui_log_pane_reset_view (self);
 
diff --git a/src/plugins/buildui/gbp-buildui-log-pane.h b/src/plugins/buildui/gbp-buildui-log-pane.h
index 0f6cab324..61d4940cb 100644
--- a/src/plugins/buildui/gbp-buildui-log-pane.h
+++ b/src/plugins/buildui/gbp-buildui-log-pane.h
@@ -20,7 +20,6 @@
 
 #pragma once
 
-#include <dazzle.h>
 #include <libide-foundry.h>
 #include <libide-gui.h>
 
diff --git a/src/plugins/buildui/gbp-buildui-log-pane.ui b/src/plugins/buildui/gbp-buildui-log-pane.ui
index 8645a4942..7481ee50d 100644
--- a/src/plugins/buildui/gbp-buildui-log-pane.ui
+++ b/src/plugins/buildui/gbp-buildui-log-pane.ui
@@ -4,22 +4,19 @@
     <child>
       <object class="GtkBox">
         <property name="orientation">horizontal</property>
-        <property name="visible">true</property>
         <child>
           <object class="GtkScrolledWindow">
-            <property name="visible">true</property>
             <child>
               <object class="IdeTerminal" id="terminal">
                 <property name="audible-bell">false</property>
-                <property name="expand">true</property>
-                <property name="visible">true</property>
+                <property name="hexpand">true</property>
+                <property name="vexpand">true</property>
               </object>
             </child>
           </object>
         </child>
         <child>
           <object class="GtkSeparator">
-            <property name="visible">true</property>
             <style>
               <class name="sidebar"/>
             </style>
@@ -27,25 +24,26 @@
         </child>
         <child>
           <object class="GtkBox">
-            <property name="border-width">2</property>
+            <property name="margin-top">2</property>
+            <property name="margin-bottom">2</property>
+            <property name="margin-start">2</property>
+            <property name="margin-end">2</property>
             <property name="hexpand">false</property>
             <property name="orientation">vertical</property>
             <property name="spacing">2</property>
             <property name="vexpand">true</property>
-            <property name="visible">true</property>
             <child>
               <object class="GtkButton" id="clear_button">
                 <property name="action-name">build-log.clear</property>
-                <property name="expand">false</property>
+                <property name="hexpand">false</property>
+                <property name="vexpand">false</property>
                 <property name="tooltip-text" translatable="yes">Clear build log</property>
-                <property name="visible">true</property>
                 <style>
                   <class name="flat"/>
                 </style>
                 <child>
                   <object class="GtkImage">
                     <property name="icon-name">edit-clear-all-symbolic</property>
-                    <property name="visible">true</property>
                   </object>
                 </child>
               </object>
@@ -53,16 +51,15 @@
             <child>
               <object class="GtkButton" id="stop_button">
                 <property name="action-name">build-manager.cancel</property>
-                <property name="expand">false</property>
+                <property name="hexpand">false</property>
+                <property name="vexpand">false</property>
                 <property name="tooltip-text" translatable="yes">Cancel build</property>
-                <property name="visible">true</property>
                 <style>
                   <class name="flat"/>
                 </style>
                 <child>
                   <object class="GtkImage">
                     <property name="icon-name">builder-build-stop-symbolic</property>
-                    <property name="visible">true</property>
                   </object>
                 </child>
               </object>
@@ -70,16 +67,15 @@
             <child>
               <object class="GtkButton" id="save_button">
                 <property name="action-name">build-log.save</property>
-                <property name="expand">false</property>
+                <property name="hexpand">false</property>
+                <property name="vexpand">false</property>
                 <property name="tooltip-text" translatable="yes">Save build log</property>
-                <property name="visible">true</property>
                 <style>
                   <class name="flat"/>
                 </style>
                 <child>
                   <object class="GtkImage">
                     <property name="icon-name">document-save-symbolic</property>
-                    <property name="visible">true</property>
                   </object>
                 </child>
               </object>
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.c 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.c
index b980071c5..2ad126a23 100644
--- a/src/plugins/buildui/gbp-buildui-omni-bar-section.c
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.c
@@ -22,7 +22,6 @@
 
 #include "config.h"
 
-#include <dazzle.h>
 #include <glib/gi18n.h>
 #include <libide-foundry.h>
 #include <libide-gui.h>
@@ -32,11 +31,10 @@
 
 struct _GbpBuilduiOmniBarSection
 {
-  GtkBin          parent_instance;
+  AdwBin          parent_instance;
 
-  DzlSignalGroup *build_manager_signals;
+  IdeSignalGroup *build_manager_signals;
 
-  GtkButton      *configure_button;
   GtkLabel       *config_ready_label;
   GtkLabel       *popover_branch_label;
   GtkLabel       *popover_build_message;
@@ -52,7 +50,7 @@ struct _GbpBuilduiOmniBarSection
   GtkRevealer    *popover_details_revealer;
 };
 
-G_DEFINE_FINAL_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, GTK_TYPE_BIN)
+G_DEFINE_FINAL_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, ADW_TYPE_BIN)
 
 static void
 gbp_buildui_omni_bar_section_notify_can_build (GbpBuilduiOmniBarSection *self,
@@ -78,7 +76,6 @@ gbp_buildui_omni_bar_section_notify_pipeline (GbpBuilduiOmniBarSection *self,
   IdePipeline *pipeline;
   const gchar *device_name = NULL;
   const gchar *runtime_name = NULL;
-  const gchar *config_id = "";
   const gchar *display_name = NULL;
 
   g_assert (IDE_IS_MAIN_THREAD ());
@@ -91,7 +88,6 @@ gbp_buildui_omni_bar_section_notify_pipeline (GbpBuilduiOmniBarSection *self,
       IdeRuntime *runtime = ide_config_get_runtime (config);
       IdeDevice *device = ide_pipeline_get_device (pipeline);
 
-      config_id = ide_config_get_id (config);
       display_name = ide_config_get_display_name (config);
 
       if (runtime != NULL)
@@ -107,7 +103,6 @@ gbp_buildui_omni_bar_section_notify_pipeline (GbpBuilduiOmniBarSection *self,
 
   gtk_label_set_label (self->popover_config_label, display_name);
   gtk_label_set_label (self->popover_device_label, device_name);
-  gtk_actionable_set_action_target (GTK_ACTIONABLE (self->configure_button), "s", config_id);
 
   if (runtime_name != NULL)
     {
@@ -203,7 +198,7 @@ gbp_buildui_omni_bar_section_build_started (GbpBuilduiOmniBarSection *self,
   gtk_revealer_set_reveal_child (self->popover_details_revealer, TRUE);
 
   gtk_label_set_label (self->popover_build_result_label, _("Building…"));
-  dzl_gtk_widget_remove_style_class (GTK_WIDGET (self->popover_build_result_label), "error");
+  gtk_widget_remove_css_class (GTK_WIDGET (self->popover_build_result_label), "error");
 
   IDE_EXIT;
 }
@@ -221,7 +216,7 @@ gbp_buildui_omni_bar_section_build_failed (GbpBuilduiOmniBarSection *self,
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
 
   gtk_label_set_label (self->popover_build_result_label, _("Failed"));
-  dzl_gtk_widget_add_style_class (GTK_WIDGET (self->popover_build_result_label), "error");
+  gtk_widget_add_css_class (GTK_WIDGET (self->popover_build_result_label), "error");
 
   IDE_EXIT;
 }
@@ -246,7 +241,7 @@ gbp_buildui_omni_bar_section_build_finished (GbpBuilduiOmniBarSection *self,
 static void
 gbp_buildui_omni_bar_section_bind_build_manager (GbpBuilduiOmniBarSection *self,
                                                  IdeBuildManager          *build_manager,
-                                                 DzlSignalGroup           *signals)
+                                                 IdeSignalGroup           *signals)
 {
   IdeContext *context;
   IdeVcs *vcs;
@@ -254,7 +249,7 @@ gbp_buildui_omni_bar_section_bind_build_manager (GbpBuilduiOmniBarSection *self,
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
-  g_assert (DZL_IS_SIGNAL_GROUP (signals));
+  g_assert (IDE_IS_SIGNAL_GROUP (signals));
 
   gbp_buildui_omni_bar_section_notify_can_build (self, NULL, build_manager);
   gbp_buildui_omni_bar_section_notify_pipeline (self, NULL, build_manager);
@@ -263,7 +258,7 @@ gbp_buildui_omni_bar_section_bind_build_manager (GbpBuilduiOmniBarSection *self,
   gbp_buildui_omni_bar_section_notify_warning_count (self, NULL, build_manager);
   gbp_buildui_omni_bar_section_notify_last_build_time (self, NULL, build_manager);
 
-  context = ide_widget_get_context (GTK_WIDGET (self));
+  context = ide_object_get_context (IDE_OBJECT (build_manager));
   vcs = ide_vcs_from_context (context);
 
   g_object_bind_property (context, "title",
@@ -276,31 +271,31 @@ gbp_buildui_omni_bar_section_bind_build_manager (GbpBuilduiOmniBarSection *self,
 }
 
 static void
-gbp_buildui_omni_bar_section_destroy (GtkWidget *widget)
+gbp_buildui_omni_bar_section_dispose (GObject *object)
 {
-  GbpBuilduiOmniBarSection *self = (GbpBuilduiOmniBarSection *)widget;
+  GbpBuilduiOmniBarSection *self = (GbpBuilduiOmniBarSection *)object;
 
   g_assert (GBP_IS_BUILDUI_OMNI_BAR_SECTION (self));
 
   if (self->build_manager_signals)
     {
-      dzl_signal_group_set_target (self->build_manager_signals, NULL);
+      ide_signal_group_set_target (self->build_manager_signals, NULL);
       g_clear_object (&self->build_manager_signals);
     }
 
-  GTK_WIDGET_CLASS (gbp_buildui_omni_bar_section_parent_class)->destroy (widget);
+  G_OBJECT_CLASS (gbp_buildui_omni_bar_section_parent_class)->dispose (object);
 }
 
 static void
 gbp_buildui_omni_bar_section_class_init (GbpBuilduiOmniBarSectionClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  widget_class->destroy = gbp_buildui_omni_bar_section_destroy;
+  object_class->dispose = gbp_buildui_omni_bar_section_dispose;
 
   gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-omni-bar-section.ui");
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, config_ready_label);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, configure_button);
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_branch_label);
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_build_message);
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiOmniBarSection, popover_build_result_label);
@@ -319,53 +314,53 @@ gbp_buildui_omni_bar_section_init (GbpBuilduiOmniBarSection *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  self->build_manager_signals = dzl_signal_group_new (IDE_TYPE_BUILD_MANAGER);
+  self->build_manager_signals = ide_signal_group_new (IDE_TYPE_BUILD_MANAGER);
   g_signal_connect_object (self->build_manager_signals,
                            "bind",
                            G_CALLBACK (gbp_buildui_omni_bar_section_bind_build_manager),
                            self,
                            G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::can-build",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_can_build),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::message",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_message),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::pipeline",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_pipeline),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::error-count",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_error_count),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::warning-count",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_warning_count),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::last-build-time",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_notify_last_build_time),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "build-started",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_build_started),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "build-failed",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_build_failed),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "build-finished",
                                    G_CALLBACK (gbp_buildui_omni_bar_section_build_finished),
                                    self,
@@ -382,5 +377,5 @@ gbp_buildui_omni_bar_section_set_context (GbpBuilduiOmniBarSection *self,
   g_return_if_fail (IDE_IS_CONTEXT (context));
 
   build_manager = ide_build_manager_from_context (context);
-  dzl_signal_group_set_target (self->build_manager_signals, build_manager);
+  ide_signal_group_set_target (self->build_manager_signals, build_manager);
 }
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.h 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.h
index a064b44f3..e49946b03 100644
--- a/src/plugins/buildui/gbp-buildui-omni-bar-section.h
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.h
@@ -20,14 +20,14 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
+#include <adwaita.h>
 #include <libide-core.h>
 
 G_BEGIN_DECLS
 
 #define GBP_TYPE_BUILDUI_OMNI_BAR_SECTION (gbp_buildui_omni_bar_section_get_type())
 
-G_DECLARE_FINAL_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, GBP, BUILDUI_OMNI_BAR_SECTION, 
GtkBin)
+G_DECLARE_FINAL_TYPE (GbpBuilduiOmniBarSection, gbp_buildui_omni_bar_section, GBP, BUILDUI_OMNI_BAR_SECTION, 
AdwBin)
 
 void gbp_buildui_omni_bar_section_set_context (GbpBuilduiOmniBarSection *self,
                                                IdeContext               *context);
diff --git a/src/plugins/buildui/gbp-buildui-omni-bar-section.ui 
b/src/plugins/buildui/gbp-buildui-omni-bar-section.ui
index 5e919801f..351831a91 100644
--- a/src/plugins/buildui/gbp-buildui-omni-bar-section.ui
+++ b/src/plugins/buildui/gbp-buildui-omni-bar-section.ui
@@ -1,236 +1,137 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.0 -->
 <interface>
-  <requires lib="gtk+" version="3.12"/>
-  <template class="GbpBuilduiOmniBarSection" parent="GtkBin">
-    <property name="can_focus">False</property>
+  <requires lib="gtk+" version="4.0"/>
+  <template class="GbpBuilduiOmniBarSection" parent="AdwBin">
     <child>
       <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
         <child>
           <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <property name="margin_start">24</property>
             <property name="margin_end">24</property>
-            <property name="margin_top">24</property>
+            <property name="margin_top">12</property>
             <property name="orientation">vertical</property>
             <child>
               <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
                 <property name="spacing">12</property>
                 <child>
                   <object class="GtkLabel" id="popover_project_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="valign">baseline</property>
                     <property name="hexpand">True</property>
                     <property name="xalign">0</property>
+                    <property name="margin-bottom">12</property>
                     <attributes>
                       <attribute name="weight" value="bold"/>
                     </attributes>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkButton">
-                    <property name="visible">True</property>
-                    <property name="focus_on_click">False</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Update project dependencies</property>
-                    <property name="valign">baseline</property>
-                    <property name="action_name">win.update-dependencies</property>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">software-update-available-symbolic</property>
-                      </object>
-                    </child>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkButton" id="configure_button">
-                    <property name="visible">True</property>
-                    <property name="focus_on_click">False</property>
-                    <property name="receives_default">False</property>
-                    <property name="tooltip_text" translatable="yes">Configure build preferences</property>
-                    <property name="valign">baseline</property>
-                    <property name="action_name">win.edit-config</property>
-                    <property name="action_target">''</property>
-                    <child>
-                      <object class="GtkImage">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="icon_name">builder-build-configure-symbolic</property>
-                      </object>
-                    </child>
-                    <style>
-                      <class name="image-button"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
             </child>
             <child>
               <object class="GtkGrid">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="row_spacing">6</property>
                 <property name="column_spacing">18</property>
                 <child>
                   <object class="GtkLabel">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Branch</property>
                     <property name="xalign">1</property>
                     <style>
                       <class name="dim-label"/>
                     </style>
+                    <layout>
+                      <property name="column">0</property>
+                      <property name="row">0</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="popover_branch_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="xalign">0</property>
+                    <layout>
+                      <property name="column">1</property>
+                      <property name="row">0</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="build_profile_title">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Build Profile</property>
                     <property name="xalign">1</property>
                     <style>
                       <class name="dim-label"/>
                     </style>
+                    <layout>
+                      <property name="column">0</property>
+                      <property name="row">1</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">1</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="popover_config_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="xalign">0</property>
+                    <layout>
+                      <property name="column">1</property>
+                      <property name="row">1</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">1</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="runtime_title">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Runtime</property>
                     <property name="xalign">1</property>
                     <style>
                       <class name="dim-label"/>
                     </style>
+                    <layout>
+                      <property name="column">0</property>
+                      <property name="row">2</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">2</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="popover_runtime_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="use_markup">True</property>
                     <property name="xalign">0</property>
+                    <layout>
+                      <property name="column">1</property>
+                      <property name="row">2</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">2</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="device_title">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Device</property>
                     <property name="xalign">1</property>
                     <style>
                       <class name="dim-label"/>
                     </style>
+                    <layout>
+                      <property name="column">0</property>
+                      <property name="row">3</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">0</property>
-                    <property name="top_attach">3</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkLabel" id="popover_device_label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="use_markup">True</property>
                     <property name="xalign">0</property>
+                    <layout>
+                      <property name="column">1</property>
+                      <property name="row">3</property>
+                    </layout>
                   </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="top_attach">3</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
         </child>
         <child>
           <object class="GtkLabel" id="config_ready_label">
-            <property name="can_focus">False</property>
             <property name="margin_top">12</property>
             <property name="label" translatable="yes">There is a problem with the current build 
configuration.</property>
             <property name="xalign">0.5</property>
@@ -241,34 +142,22 @@
               <class name="warning"/>
             </style>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
         <child>
           <object class="GtkRevealer" id="popover_details_revealer">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
             <child>
               <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
                 <property name="margin_start">24</property>
                 <property name="margin_end">24</property>
                 <property name="margin_top">24</property>
                 <property name="orientation">vertical</property>
                 <child>
                   <object class="GtkBox">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="hexpand">True</property>
                     <property name="spacing">12</property>
+                    <property name="margin-bottom">12</property>
                     <child>
                       <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="valign">baseline</property>
                         <property name="label" translatable="yes">Build status</property>
                         <property name="xalign">0</property>
@@ -276,275 +165,128 @@
                           <attribute name="weight" value="bold"/>
                         </attributes>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="popover_build_message">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="valign">baseline</property>
                         <property name="hexpand">True</property>
                         <property name="ellipsize">end</property>
                         <property name="xalign">0</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkButton">
-                        <property name="visible">True</property>
-                        <property name="focus_on_click">False</property>
-                        <property name="receives_default">False</property>
-                        <property name="tooltip_text" translatable="yes">View build console 
contents</property>
-                        <property name="halign">end</property>
-                        <property name="valign">baseline</property>
-                        <property name="action_name">win.view-output</property>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="icon_name">builder-build-info-symbolic</property>
-                          </object>
-                        </child>
-                        <style>
-                          <class name="image-button"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="GtkGrid" id="build_status_grid">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
                     <property name="row_spacing">6</property>
                     <property name="column_spacing">18</property>
                     <child>
                       <object class="GtkLabel" id="last_build_title">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">False</property>
                         <property name="label" translatable="yes">Last build</property>
                         <property name="xalign">1</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
+                        <layout>
+                          <property name="column">0</property>
+                          <property name="row">0</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="popover_last_build_time_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="width_chars">10</property>
                         <property name="xalign">0</property>
+                        <layout>
+                          <property name="column">1</property>
+                          <property name="row">0</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="build_result_title">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">False</property>
                         <property name="label" translatable="yes">Build result</property>
                         <property name="xalign">1</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
+                        <layout>
+                          <property name="column">0</property>
+                          <property name="row">1</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="popover_build_result_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="width_chars">10</property>
                         <property name="xalign">0</property>
+                        <layout>
+                          <property name="column">1</property>
+                          <property name="row">1</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="error_title">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">False</property>
                         <property name="label" translatable="yes">Errors</property>
                         <property name="xalign">1</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
+                        <layout>
+                          <property name="column">2</property>
+                          <property name="row">0</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">2</property>
-                        <property name="top_attach">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="popover_errors_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="label">0</property>
                         <property name="width_chars">10</property>
                         <property name="xalign">0</property>
+                        <layout>
+                          <property name="column">3</property>
+                          <property name="row">0</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">3</property>
-                        <property name="top_attach">0</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="warning_title">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">False</property>
                         <property name="label" translatable="yes">Warnings</property>
                         <property name="xalign">1</property>
                         <style>
                           <class name="dim-label"/>
                         </style>
+                        <layout>
+                          <property name="column">2</property>
+                          <property name="row">1</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">2</property>
-                        <property name="top_attach">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="popover_warnings_label">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="label">0</property>
                         <property name="width_chars">10</property>
                         <property name="xalign">0</property>
+                        <layout>
+                          <property name="column">3</property>
+                          <property name="row">1</property>
+                        </layout>
                       </object>
-                      <packing>
-                        <property name="left_attach">3</property>
-                        <property name="top_attach">1</property>
-                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
             </child>
           </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="margin_start">24</property>
-            <property name="margin_end">24</property>
-            <property name="margin_top">24</property>
-            <property name="spacing">6</property>
-            <!-- TRANSLATORS: valid values are True or False. DO NOT TRANSLATE False and True, otherwise 
it'll break the layout of the button. If the buttons in the build popover are too large because of 
translations, set to False to disable homogeneous sizing -->
-            <property name="homogeneous" translatable="yes">True</property>
-            <child>
-              <object class="GtkButton">
-                <property name="label" translatable="yes">_Build</property>
-                <property name="use-underline">True</property>
-                <property name="visible">True</property>
-                <property name="receives_default">True</property>
-                <property name="action_name">build-manager.build</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton">
-                <property name="label" translatable="yes">_Rebuild</property>
-                <property name="use-underline">True</property>
-                <property name="visible">True</property>
-                <property name="receives_default">True</property>
-                <property name="action_name">build-manager.rebuild</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton">
-                <property name="label" translatable="yes">_Clean</property>
-                <property name="use-underline">True</property>
-                <property name="visible">True</property>
-                <property name="receives_default">True</property>
-                <property name="action_name">build-manager.clean</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton">
-                <property name="label" translatable="yes">_Export Bundle</property>
-                <property name="use-underline">True</property>
-                <property name="visible">True</property>
-                <property name="receives_default">True</property>
-                <property name="action_name">build-manager.export</property>
-                <style>
-                  <class name="suggested-action"/>
-                </style>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">3</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
         </child>
         <style>
           <class name="popover-content-area"/>
diff --git a/src/plugins/buildui/gbp-buildui-pane.c b/src/plugins/buildui/gbp-buildui-pane.c
index 6be133dd1..1daec0197 100644
--- a/src/plugins/buildui/gbp-buildui-pane.c
+++ b/src/plugins/buildui/gbp-buildui-pane.c
@@ -23,8 +23,10 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+
 #include <libide-editor.h>
 #include <libide-foundry.h>
+#include <libide-gtk.h>
 
 #include "ide-pipeline-stage-private.h"
 
@@ -36,32 +38,17 @@ struct _GbpBuilduiPane
   IdePane              parent_instance;
 
   /* Owned references */
-  GHashTable          *diags_hash;
-  IdePipeline    *pipeline;
-  DzlSignalGroup      *pipeline_signals;
+  IdePipeline         *pipeline;
+  IdeSignalGroup      *pipeline_signals;
 
   /* Template widgets */
   GtkLabel            *build_status_label;
   GtkLabel            *time_completed_label;
-  GtkNotebook         *notebook;
-  GtkScrolledWindow   *errors_page;
-  IdeFancyTreeView    *errors_tree_view;
-  GtkScrolledWindow   *warnings_page;
-  IdeFancyTreeView    *warnings_tree_view;
-  GtkListStore        *diagnostics_store;
   GtkListBox          *stages_list_box;
-
-  guint                error_count;
-  guint                warning_count;
 };
 
 G_DEFINE_FINAL_TYPE (GbpBuilduiPane, gbp_buildui_pane, IDE_TYPE_PANE)
 
-enum {
-  COLUMN_DIAGNOSTIC,
-  LAST_COLUMN
-};
-
 enum {
   PROP_0,
   PROP_PIPELINE,
@@ -70,83 +57,6 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
-static void
-set_warnings_label (GbpBuilduiPane *self,
-                    const gchar   *label)
-{
-  gtk_container_child_set (GTK_CONTAINER (self->notebook), GTK_WIDGET (self->warnings_page),
-                           "tab-label", label,
-                           NULL);
-}
-
-static void
-set_errors_label (GbpBuilduiPane *self,
-                  const gchar   *label)
-{
-  gtk_container_child_set (GTK_CONTAINER (self->notebook), GTK_WIDGET (self->errors_page),
-                           "tab-label", label,
-                           NULL);
-}
-
-static void
-gbp_buildui_pane_diagnostic (GbpBuilduiPane   *self,
-                             IdeDiagnostic    *diagnostic,
-                             IdePipeline *pipeline)
-{
-  IdeDiagnosticSeverity severity;
-  guint hash;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_BUILDUI_PANE (self));
-  g_assert (diagnostic != NULL);
-  g_assert (IDE_IS_PIPELINE (pipeline));
-
-  severity = ide_diagnostic_get_severity (diagnostic);
-
-  if (severity == IDE_DIAGNOSTIC_WARNING)
-    {
-      g_autofree gchar *label = NULL;
-
-      self->warning_count++;
-
-      label = g_strdup_printf ("%s (%u)", _("Warnings"), self->warning_count);
-      set_warnings_label (self, label);
-    }
-  else if (severity == IDE_DIAGNOSTIC_ERROR || severity == IDE_DIAGNOSTIC_FATAL)
-    {
-      g_autofree gchar *label = NULL;
-
-      self->error_count++;
-
-      label = g_strdup_printf ("%s (%u)", _("Errors"), self->error_count);
-      set_errors_label (self, label);
-    }
-  else
-    {
-      /* TODO: Figure out design for "Others" Column like Notes? */
-    }
-
-  hash = ide_diagnostic_hash (diagnostic);
-
-  if (g_hash_table_insert (self->diags_hash, GUINT_TO_POINTER (hash), NULL))
-    {
-      GtkTreeIter iter;
-
-      dzl_gtk_list_store_insert_sorted (self->diagnostics_store,
-                                        &iter,
-                                        diagnostic,
-                                        COLUMN_DIAGNOSTIC,
-                                        (GCompareDataFunc)ide_diagnostic_compare,
-                                        NULL);
-      gtk_list_store_set (self->diagnostics_store, &iter,
-                          COLUMN_DIAGNOSTIC, diagnostic,
-                          -1);
-    }
-
-  IDE_EXIT;
-}
-
 static void
 gbp_buildui_pane_update_running_time (GbpBuilduiPane *self)
 {
@@ -164,41 +74,16 @@ gbp_buildui_pane_update_running_time (GbpBuilduiPane *self)
       build_manager = ide_build_manager_from_context (context);
 
       span = ide_build_manager_get_running_time (build_manager);
-      text = dzl_g_time_span_to_label (span);
+      text = ide_g_time_span_to_label (span);
       gtk_label_set_label (self->time_completed_label, text);
     }
   else
     gtk_label_set_label (self->time_completed_label, "—");
 }
 
-static void
-gbp_buildui_pane_started (GbpBuilduiPane   *self,
-                          IdePipelinePhase     phase,
-                          IdePipeline *pipeline)
-{
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_BUILDUI_PANE (self));
-  g_assert (IDE_IS_PIPELINE (pipeline));
-
-  if (phase >= IDE_PIPELINE_PHASE_BUILD)
-    {
-      self->error_count = 0;
-      self->warning_count = 0;
-
-      set_warnings_label (self, _("Warnings"));
-      set_errors_label (self, _("Errors"));
-
-      gtk_list_store_clear (self->diagnostics_store);
-      g_hash_table_remove_all (self->diags_hash);
-    }
-
-  IDE_EXIT;
-}
-
 static GtkWidget *
 gbp_buildui_pane_create_stage_row_cb (gpointer data,
-                                     gpointer user_data)
+                                      gpointer user_data)
 {
   IdePipelineStage *stage = data;
 
@@ -209,22 +94,17 @@ gbp_buildui_pane_create_stage_row_cb (gpointer data,
 }
 
 static void
-gbp_buildui_pane_bind_pipeline (GbpBuilduiPane   *self,
-                                IdePipeline *pipeline,
-                                DzlSignalGroup   *signals)
+gbp_buildui_pane_bind_pipeline (GbpBuilduiPane *self,
+                                IdePipeline    *pipeline,
+                                IdeSignalGroup *signals)
 {
   g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (IDE_IS_PIPELINE (pipeline));
   g_assert (G_IS_LIST_MODEL (pipeline));
   g_assert (self->pipeline == NULL);
-  g_assert (DZL_IS_SIGNAL_GROUP (signals));
+  g_assert (IDE_IS_SIGNAL_GROUP (signals));
 
   self->pipeline = g_object_ref (pipeline);
-  self->error_count = 0;
-  self->warning_count = 0;
-
-  set_warnings_label (self, _("Warnings"));
-  set_errors_label (self, _("Errors"));
 
   gtk_label_set_label (self->time_completed_label, "—");
   gtk_label_set_label (self->build_status_label, "—");
@@ -239,7 +119,7 @@ gbp_buildui_pane_bind_pipeline (GbpBuilduiPane   *self,
 
 static void
 gbp_buildui_pane_unbind_pipeline (GbpBuilduiPane *self,
-                                  DzlSignalGroup *signals)
+                                  IdeSignalGroup *signals)
 {
   g_return_if_fail (GBP_IS_BUILDUI_PANE (self));
   g_return_if_fail (!self->pipeline || IDE_IS_PIPELINE (self->pipeline));
@@ -248,11 +128,11 @@ gbp_buildui_pane_unbind_pipeline (GbpBuilduiPane *self,
 
   if (!gtk_widget_in_destruction (GTK_WIDGET (self)))
     {
-      g_hash_table_remove_all (self->diags_hash);
-      gtk_list_store_clear (self->diagnostics_store);
-      gtk_container_foreach (GTK_CONTAINER (self->stages_list_box),
-                             (GtkCallback) gtk_widget_destroy,
-                             NULL);
+      GtkWidget *child;
+
+      while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->stages_list_box))) != NULL)
+        gtk_list_box_remove (self->stages_list_box, child);
+
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PIPELINE]);
     }
 }
@@ -265,94 +145,7 @@ gbp_buildui_pane_set_pipeline (GbpBuilduiPane   *self,
   g_return_if_fail (!pipeline || IDE_IS_PIPELINE (pipeline));
 
   if (self->pipeline_signals != NULL)
-    dzl_signal_group_set_target (self->pipeline_signals, pipeline);
-}
-
-static void
-gbp_buildui_pane_diagnostic_activated (GbpBuilduiPane    *self,
-                                       GtkTreePath       *path,
-                                       GtkTreeViewColumn *colun,
-                                       GtkTreeView       *tree_view)
-{
-  g_autoptr(IdeDiagnostic) diagnostic = NULL;
-  IdeWorkspace *workspace;
-  IdeLocation *loc;
-  GtkTreeModel *model;
-  IdeSurface *surface;
-  GtkTreeIter iter;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_BUILDUI_PANE (self));
-  g_assert (path != NULL);
-  g_assert (GTK_IS_TREE_VIEW_COLUMN (colun));
-  g_assert (GTK_IS_TREE_VIEW (tree_view));
-
-  model = gtk_tree_view_get_model (tree_view);
-  if (!gtk_tree_model_get_iter (model, &iter, path))
-    IDE_EXIT;
-
-  gtk_tree_model_get (model, &iter,
-                      COLUMN_DIAGNOSTIC, &diagnostic,
-                      -1);
-
-  if (diagnostic == NULL || !(loc = ide_diagnostic_get_location (diagnostic)))
-    IDE_EXIT;
-
-  workspace = ide_widget_get_workspace (GTK_WIDGET (self));
-  surface = ide_workspace_get_surface_by_name (workspace, "editor");
-  ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (surface), loc);
-
-  IDE_EXIT;
-}
-
-static void
-gbp_buildui_pane_text_func (GtkCellLayout   *layout,
-                            GtkCellRenderer *renderer,
-                            GtkTreeModel    *model,
-                            GtkTreeIter     *iter,
-                            gpointer         user_data)
-{
-  IdeCellRendererFancy *fancy = (IdeCellRendererFancy *)renderer;
-  g_autoptr(IdeDiagnostic) diagnostic = NULL;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_DIAGNOSTIC, &diagnostic,
-                      -1);
-
-  if G_LIKELY (diagnostic != NULL)
-    {
-      g_autofree gchar *title = NULL;
-      g_autofree gchar *name = NULL;
-      IdeLocation *location;
-      const gchar *text;
-      GFile *file = NULL;
-      guint line = 0;
-      guint column = 0;
-
-      location = ide_diagnostic_get_location (diagnostic);
-
-      if (location != NULL)
-        {
-          if ((file = ide_location_get_file (location)))
-            {
-              name = g_file_get_basename (file);
-              line = ide_location_get_line (location);
-              column = ide_location_get_line_offset (location);
-            }
-        }
-
-      title = g_strdup_printf ("%s:%u:%u", name ?: "", line + 1, column + 1);
-      ide_cell_renderer_fancy_take_title (fancy, g_steal_pointer (&title));
-
-      text = ide_diagnostic_get_text (diagnostic);
-      ide_cell_renderer_fancy_set_body (fancy, text);
-    }
-  else
-    {
-      ide_cell_renderer_fancy_set_title (fancy, NULL);
-      ide_cell_renderer_fancy_set_body (fancy, NULL);
-    }
+    ide_signal_group_set_target (self->pipeline_signals, pipeline);
 }
 
 static void
@@ -362,7 +155,6 @@ gbp_buildui_pane_notify_message (GbpBuilduiPane  *self,
 {
   g_autofree gchar *message = NULL;
   IdePipeline *pipeline;
-  GtkStyleContext *style;
 
   g_assert (GBP_IS_BUILDUI_PANE (self));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
@@ -372,12 +164,10 @@ gbp_buildui_pane_notify_message (GbpBuilduiPane  *self,
 
   gtk_label_set_label (self->build_status_label, message);
 
-  style = gtk_widget_get_style_context (GTK_WIDGET (self->build_status_label));
-
   if (ide_pipeline_get_phase (pipeline) == IDE_PIPELINE_PHASE_FAILED)
-    gtk_style_context_add_class (style, GTK_STYLE_CLASS_ERROR);
+    gtk_widget_add_css_class (GTK_WIDGET (self->build_status_label), "error");
   else
-    gtk_style_context_remove_class (style, GTK_STYLE_CLASS_ERROR);
+    gtk_widget_remove_css_class (GTK_WIDGET (self->build_status_label), "error");
 }
 
 static void
@@ -430,86 +220,6 @@ gbp_buildui_pane_context_handler (GtkWidget  *widget,
   IDE_EXIT;
 }
 
-static gboolean
-gbp_buildui_pane_diagnostic_tooltip (GbpBuilduiPane *self,
-                                     gint            x,
-                                     gint            y,
-                                     gboolean        keyboard_mode,
-                                     GtkTooltip     *tooltip,
-                                     GtkTreeView    *tree_view)
-{
-  g_autoptr(GtkTreePath) path = NULL;
-  GtkTreeModel *model = NULL;
-
-  g_assert (GBP_IS_BUILDUI_PANE (self));
-  g_assert (GTK_IS_TOOLTIP (tooltip));
-  g_assert (GTK_IS_TREE_VIEW (tree_view));
-
-  if (NULL == (model = gtk_tree_view_get_model (tree_view)))
-    return FALSE;
-
-  if (gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, NULL, NULL, NULL))
-    {
-      GtkTreeIter iter;
-
-      if (gtk_tree_model_get_iter (model, &iter, path))
-        {
-         g_autoptr(IdeDiagnostic) diag = NULL;
-
-         gtk_tree_model_get (model, &iter,
-                             COLUMN_DIAGNOSTIC, &diag,
-                             -1);
-
-         if (diag != NULL)
-           {
-             g_autofree gchar *text = ide_diagnostic_get_text_for_display (diag);
-
-             gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
-             gtk_tooltip_set_text (tooltip, text);
-             return TRUE;
-           }
-       }
-    }
-
-  return FALSE;
-}
-
-static gboolean
-diagnostic_is_warning (GtkTreeModel *model,
-                       GtkTreeIter  *iter,
-                       gpointer      user_data)
-{
-  g_autoptr(IdeDiagnostic) diag = NULL;
-  IdeDiagnosticSeverity severity = 0;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_DIAGNOSTIC, &diag,
-                      -1);
-
-  if (diag != NULL)
-    severity = ide_diagnostic_get_severity (diag);
-
-  return severity <= IDE_DIAGNOSTIC_WARNING;
-}
-
-static gboolean
-diagnostic_is_error (GtkTreeModel *model,
-                     GtkTreeIter  *iter,
-                     gpointer      user_data)
-{
-  g_autoptr(IdeDiagnostic) diag = NULL;
-  IdeDiagnosticSeverity severity = 0;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_DIAGNOSTIC, &diag,
-                      -1);
-
-  if (diag != NULL)
-    severity = ide_diagnostic_get_severity (diag);
-
-  return severity > IDE_DIAGNOSTIC_WARNING;
-}
-
 static void
 gbp_buildui_pane_stage_row_activated (GbpBuilduiPane     *self,
                                       GbpBuilduiStageRow *row,
@@ -531,24 +241,22 @@ gbp_buildui_pane_stage_row_activated (GbpBuilduiPane     *self,
   phase = _ide_pipeline_stage_get_phase (stage);
 
   ide_pipeline_build_async (self->pipeline,
-                                  phase & IDE_PIPELINE_PHASE_MASK,
-                                  NULL, NULL, NULL);
+                            phase & IDE_PIPELINE_PHASE_MASK,
+                            NULL, NULL, NULL);
 }
 
 static void
-gbp_buildui_pane_destroy (GtkWidget *widget)
+gbp_buildui_pane_dispose (GObject *object)
 {
-  GbpBuilduiPane *self = (GbpBuilduiPane *)widget;
+  GbpBuilduiPane *self = (GbpBuilduiPane *)object;
 
   if (self->pipeline_signals != NULL)
-    dzl_signal_group_set_target (self->pipeline_signals, NULL);
-
-  g_clear_pointer (&self->diags_hash, g_hash_table_unref);
+    ide_signal_group_set_target (self->pipeline_signals, NULL);
 
   g_clear_object (&self->pipeline_signals);
   g_clear_object (&self->pipeline);
 
-  GTK_WIDGET_CLASS (gbp_buildui_pane_parent_class)->destroy (widget);
+  G_OBJECT_CLASS (gbp_buildui_pane_parent_class)->dispose (object);
 }
 
 static void
@@ -595,8 +303,7 @@ gbp_buildui_pane_class_init (GbpBuilduiPaneClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  widget_class->destroy = gbp_buildui_pane_destroy;
-
+  object_class->dispose = gbp_buildui_pane_dispose;
   object_class->get_property = gbp_buildui_pane_get_property;
   object_class->set_property = gbp_buildui_pane_set_property;
 
@@ -613,96 +320,32 @@ gbp_buildui_pane_class_init (GbpBuilduiPaneClass *klass)
   gtk_widget_class_set_css_name (widget_class, "buildpanel");
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, build_status_label);
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, time_completed_label);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, notebook);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, errors_page);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, errors_tree_view);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, warnings_page);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, warnings_tree_view);
-  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, diagnostics_store);
   gtk_widget_class_bind_template_child (widget_class, GbpBuilduiPane, stages_list_box);
 
-  g_type_ensure (IDE_TYPE_CELL_RENDERER_FANCY);
   g_type_ensure (IDE_TYPE_DIAGNOSTIC);
-  g_type_ensure (IDE_TYPE_FANCY_TREE_VIEW);
 }
 
 static void
 gbp_buildui_pane_init (GbpBuilduiPane *self)
 {
-  GtkTreeModel *filter;
-
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  self->pipeline_signals = dzl_signal_group_new (IDE_TYPE_PIPELINE);
-
+  self->pipeline_signals = ide_signal_group_new (IDE_TYPE_PIPELINE);
   g_signal_connect_object (self->pipeline_signals,
                            "bind",
                            G_CALLBACK (gbp_buildui_pane_bind_pipeline),
                            self,
                            G_CONNECT_SWAPPED);
-
   g_signal_connect_object (self->pipeline_signals,
                            "unbind",
                            G_CALLBACK (gbp_buildui_pane_unbind_pipeline),
                            self,
                            G_CONNECT_SWAPPED);
 
-  dzl_signal_group_connect_object (self->pipeline_signals,
-                                   "diagnostic",
-                                   G_CALLBACK (gbp_buildui_pane_diagnostic),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-
-  dzl_signal_group_connect_object (self->pipeline_signals,
-                                   "started",
-                                   G_CALLBACK (gbp_buildui_pane_started),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-
-  self->diags_hash = g_hash_table_new (NULL, NULL);
-
-  g_object_set (self, "title", _("Build Issues"), NULL);
+  panel_widget_set_title (PANEL_WIDGET (self), _("Build Pipeline"));
 
   ide_widget_set_context_handler (self, gbp_buildui_pane_context_handler);
 
-  g_signal_connect_swapped (self->warnings_tree_view,
-                           "row-activated",
-                           G_CALLBACK (gbp_buildui_pane_diagnostic_activated),
-                           self);
-
-  g_signal_connect_swapped (self->warnings_tree_view,
-                           "query-tooltip",
-                           G_CALLBACK (gbp_buildui_pane_diagnostic_tooltip),
-                           self);
-
-  g_signal_connect_swapped (self->errors_tree_view,
-                           "row-activated",
-                           G_CALLBACK (gbp_buildui_pane_diagnostic_activated),
-                           self);
-
-  g_signal_connect_swapped (self->errors_tree_view,
-                           "query-tooltip",
-                           G_CALLBACK (gbp_buildui_pane_diagnostic_tooltip),
-                           self);
-
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (self->diagnostics_store), NULL);
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
-                                          diagnostic_is_warning, NULL, NULL);
-  gtk_tree_view_set_model (GTK_TREE_VIEW (self->warnings_tree_view), GTK_TREE_MODEL (filter));
-  g_object_unref (filter);
-
-  filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (self->diagnostics_store), NULL);
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
-                                          diagnostic_is_error, NULL, NULL);
-  gtk_tree_view_set_model (GTK_TREE_VIEW (self->errors_tree_view), GTK_TREE_MODEL (filter));
-  g_object_unref (filter);
-
-  ide_fancy_tree_view_set_data_func (IDE_FANCY_TREE_VIEW (self->warnings_tree_view),
-                                     gbp_buildui_pane_text_func, self, NULL);
-
-  ide_fancy_tree_view_set_data_func (IDE_FANCY_TREE_VIEW (self->errors_tree_view),
-                                     gbp_buildui_pane_text_func, self, NULL);
-
   g_signal_connect_swapped (self->stages_list_box,
                             "row-activated",
                             G_CALLBACK (gbp_buildui_pane_stage_row_activated),
diff --git a/src/plugins/buildui/gbp-buildui-pane.h b/src/plugins/buildui/gbp-buildui-pane.h
index 0db43563b..fff271afd 100644
--- a/src/plugins/buildui/gbp-buildui-pane.h
+++ b/src/plugins/buildui/gbp-buildui-pane.h
@@ -29,7 +29,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbpBuilduiPane, gbp_buildui_pane, GBP, BUILDUI_PANE, IdePane)
 
-void gbp_buildui_pane_set_pipeline (GbpBuilduiPane   *self,
-                                    IdePipeline *pipeline);
+void gbp_buildui_pane_set_pipeline (GbpBuilduiPane *self,
+                                    IdePipeline    *pipeline);
 
 G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-pane.ui b/src/plugins/buildui/gbp-buildui-pane.ui
index 8511ca473..c025b32f0 100644
--- a/src/plugins/buildui/gbp-buildui-pane.ui
+++ b/src/plugins/buildui/gbp-buildui-pane.ui
@@ -1,21 +1,24 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <template class="GbpBuilduiPane" parent="IdePane">
+    <property name="title" translatable="yes">Build Issues</property>
+    <property name="icon-name">builder-build-issues-symbolic</property>
     <child>
-      <object class="DzlMultiPaned">
-        <property name="orientation">vertical</property>
-        <property name="visible">true</property>
+      <object class="GtkScrolledWindow">
+        <property name="propagate-natural-height">true</property>
         <child>
           <object class="GtkGrid">
-            <property name="margin">6</property>
+            <property name="margin-top">6</property>
+            <property name="margin-bottom">6</property>
+            <property name="margin-start">6</property>
+            <property name="margin-end">6</property>
             <property name="column-spacing">6</property>
             <property name="row-spacing">6</property>
-            <property name="expand">false</property>
-            <property name="visible">true</property>
+            <property name="hexpand">false</property>
+            <property name="vexpand">false</property>
             <child>
               <object class="GtkLabel">
                 <property name="label" translatable="yes">Build status:</property>
-                <property name="visible">true</property>
                 <property name="xalign">1.0</property>
                 <style>
                   <class name="dim-label"/>
@@ -23,16 +26,15 @@
                 <attributes>
                   <attribute name="scale" value="0.8333"/>
                 </attributes>
+                <layout>
+                  <property name="row">0</property>
+                  <property name="column">0</property>
+                </layout>
               </object>
-              <packing>
-                <property name="top-attach">0</property>
-                <property name="left-attach">0</property>
-              </packing>
             </child>
             <child>
               <object class="GtkLabel">
                 <property name="label" translatable="yes">Time completed:</property>
-                <property name="visible">true</property>
                 <property name="xalign">1.0</property>
                 <style>
                   <class name="dim-label"/>
@@ -40,136 +42,64 @@
                 <attributes>
                   <attribute name="scale" value="0.8333"/>
                 </attributes>
+                <layout>
+                  <property name="row">1</property>
+                  <property name="column">0</property>
+                </layout>
               </object>
-              <packing>
-                <property name="top-attach">1</property>
-                <property name="left-attach">0</property>
-              </packing>
             </child>
             <child>
               <object class="GtkLabel" id="build_status_label">
                 <property name="label" translatable="yes">—</property>
                 <property name="hexpand">true</property>
-                <property name="visible">true</property>
                 <property name="xalign">0.0</property>
                 <attributes>
                   <attribute name="scale" value="0.8333"/>
                 </attributes>
+                <layout>
+                  <property name="row">0</property>
+                  <property name="column">1</property>
+                </layout>
               </object>
-              <packing>
-                <property name="top-attach">0</property>
-                <property name="left-attach">1</property>
-              </packing>
             </child>
             <child>
               <object class="GtkLabel" id="time_completed_label">
                 <property name="label" translatable="yes">—</property>
                 <property name="hexpand">true</property>
-                <property name="visible">true</property>
                 <property name="xalign">0.0</property>
                 <attributes>
                   <attribute name="scale" value="0.8333"/>
                 </attributes>
+                <layout>
+                  <property name="row">1</property>
+                  <property name="column">1</property>
+                </layout>
               </object>
-              <packing>
-                <property name="top-attach">1</property>
-                <property name="left-attach">1</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkExpander">
-                <property name="visible">true</property>
-                <property name="label" translatable="yes">Build Details</property>
+              <object class="AdwPreferencesGroup">
+                <property name="title" translatable="yes">Build Pipeline</property>
+                <layout>
+                  <property name="row">2</property>
+                  <property name="column">0</property>
+                  <property name="column-span">2</property>
+                </layout>
                 <child>
-                  <object class="GtkScrolledWindow">
-                    <property name="propagate-natural-height">true</property>
-                    <property name="visible">true</property>
-                    <child>
-                      <object class="GtkListBox" id="stages_list_box">
-                        <property name="selection-mode">none</property>
-                        <property name="visible">true</property>
-                        <child type="placeholder">
-                          <object class="GtkLabel">
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                            <property name="label" translatable="yes">Build pipeline is empty</property>
-                            <property name="xalign">0.5</property>
-                            <property name="ypad">12</property>
-                            <property name="visible">true</property>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="top-attach">2</property>
-                <property name="left-attach">0</property>
-                <property name="width">2</property>
-              </packing>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkNotebook" id="notebook">
-            <property name="show-border">false</property>
-            <property name="vexpand">true</property>
-            <property name="visible">true</property>
-            <child>
-              <object class="GtkScrolledWindow" id="warnings_page">
-                <property name="visible">true</property>
-                <child>
-                  <object class="IdeFancyTreeView" id="warnings_tree_view">
-                    <property name="has-tooltip">true</property>
-                    <property name="visible">true</property>
+                  <object class="GtkListBox" id="stages_list_box">
+                    <property name="margin-bottom">6</property>
+                    <property name="margin-start">6</property>
+                    <property name="margin-end">6</property>
+                    <property name="selection-mode">none</property>
                     <style>
-                      <class name="i-wanna-be-listbox"/>
+                      <class name="boxed-list"/>
                     </style>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection">
-                        <property name="mode">none</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="position">0</property>
-                <property name="tab-label" translatable="yes">Warnings</property>
-                <property name="tab-expand">true</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="errors_page">
-                <property name="visible">true</property>
-                <child>
-                  <object class="IdeFancyTreeView" id="errors_tree_view">
-                    <property name="has-tooltip">true</property>
-                    <property name="visible">true</property>
-                    <child internal-child="selection">
-                      <object class="GtkTreeSelection">
-                        <property name="mode">none</property>
-                      </object>
-                    </child>
                   </object>
                 </child>
               </object>
-              <packing>
-                <property name="position">1</property>
-                <property name="tab-label" translatable="yes">Errors</property>
-                <property name="tab-expand">true</property>
-              </packing>
             </child>
           </object>
         </child>
       </object>
     </child>
   </template>
-  <object class="GtkListStore" id="diagnostics_store">
-    <columns>
-      <column type="IdeDiagnostic"/>
-    </columns>
-  </object>
 </interface>
diff --git a/src/plugins/buildui/gbp-buildui-preferences-addin.c 
b/src/plugins/buildui/gbp-buildui-preferences-addin.c
new file mode 100644
index 000000000..fb5608b4e
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-preferences-addin.c
@@ -0,0 +1,474 @@
+/* gbp-buildui-preferences-addin.h
+ *
+ * Copyright 2022 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *           2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-preferences-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-sourceview.h>
+
+#include "gbp-buildui-preferences-addin.h"
+#include "gbp-buildui-runtime-categories.h"
+#include "gbp-buildui-runtime-row.h"
+
+struct _GbpBuilduiPreferencesAddin
+{
+  GObject parent_instance;
+};
+
+static GtkWidget *
+create_overview_row (const char *title,
+                     const char *value)
+{
+  GtkWidget *row;
+
+  row = g_object_new (ADW_TYPE_ENTRY_ROW,
+                      "title", title,
+                      "text", value,
+                      "editable", FALSE,
+                      "show-apply-button", FALSE,
+                      NULL);
+
+  return row;
+}
+
+static void
+overview_func (const char                   *page_name,
+               const IdePreferenceItemEntry *entry,
+               AdwPreferencesGroup          *group,
+               gpointer                      user_data)
+{
+  IdeContext *context = user_data;
+
+  g_assert (IDE_IS_CONTEXT (context));
+  g_assert (ADW_IS_PREFERENCES_GROUP (group));
+
+  if (FALSE) {}
+  else if (g_strcmp0 (entry->name, "kind") == 0)
+    {
+      IdeBuildSystem *build_system = ide_build_system_from_context (context);
+      g_autofree char *name = ide_build_system_get_display_name (build_system);
+
+      adw_preferences_group_add (group, create_overview_row (entry->title, name));
+    }
+  else if (g_strcmp0 (entry->name, "srcdir") == 0)
+    {
+      g_autoptr(GFile) workdir = ide_context_ref_workdir (context);
+      g_autofree char *text = NULL;
+
+      if (g_file_is_native (workdir))
+        text = ide_path_collapse (g_file_peek_path (workdir));
+      else
+        text = g_file_get_uri (workdir);
+
+      adw_preferences_group_add (group, create_overview_row (entry->title, text));
+    }
+  else if (g_strcmp0 (entry->name, "vcsuri") == 0)
+    {
+      IdeVcs *vcs = ide_vcs_from_context (context);
+      g_autofree char *name = NULL;
+
+      if (vcs != NULL)
+        name = ide_vcs_get_display_name (vcs);
+      else
+        name = g_strdup (_("No Version Control"));
+
+      adw_preferences_group_add (group, create_overview_row (entry->title, name));
+    }
+}
+
+static const IdePreferenceGroupEntry overview_groups[] = {
+  { "overview", "project",        0, N_("Project") },
+  { "overview", "runtime",      100, N_("Runtime") },
+};
+
+static const IdePreferenceItemEntry overview_items[] = {
+  { "overview", "project", "kind", 0, overview_func, N_("Build System") },
+  { "overview", "project", "srcdir", 0, overview_func, N_("Source Directory") },
+  { "overview", "project", "vcsuri", 0, overview_func, N_("Version Control") },
+};
+
+static gboolean
+treat_null_as_empty (GBinding     *binding,
+                     const GValue *from_value,
+                     GValue       *to_value,
+                     gpointer      user_data)
+{
+  const char *str = g_value_get_string (from_value);
+  g_value_set_string (to_value, str ?: "");
+  return TRUE;
+}
+
+static void
+add_description_row (AdwPreferencesGroup *group,
+                     const char          *title,
+                     const char          *value)
+{
+  GtkWidget *label;
+  GtkWidget *row;
+
+  label = g_object_new (GTK_TYPE_LABEL,
+                        "label", value,
+                        "tooltip-text", value,
+                        "selectable", TRUE,
+                        "max-width-chars", 30,
+                        NULL);
+  gtk_widget_add_css_class (label, "dim-label");
+
+  row = g_object_new (ADW_TYPE_ACTION_ROW,
+                      "title", title,
+                      NULL);
+  adw_action_row_add_suffix (ADW_ACTION_ROW (row), label);
+  adw_preferences_group_add (group, row);
+}
+
+static void
+add_entry_row (AdwPreferencesGroup *group,
+               const char          *title,
+               gpointer             source_object,
+               const char          *bind_property)
+{
+  GtkWidget *row;
+
+  row = g_object_new (ADW_TYPE_ENTRY_ROW,
+                      "title", title,
+                      NULL);
+
+  g_object_bind_property_full (source_object, bind_property,
+                               row, "text",
+                               G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
+                               treat_null_as_empty, NULL, NULL, NULL);
+
+  adw_preferences_group_add (group, row);
+}
+
+static void
+create_general_widgetry (const char                   *page_name,
+                         const IdePreferenceItemEntry *entry,
+                         AdwPreferencesGroup          *group,
+                         gpointer                      user_data)
+{
+  g_autoptr(GFile) workdir = NULL;
+  IdeConfig *config = user_data;
+  IdeConfigManager *config_manager;
+  IdeBuildSystem *build_system;
+  IdeContext *context;
+  GtkWidget *box;
+  static const struct {
+    const gchar *label;
+    const gchar *action;
+    const gchar *tooltip;
+    const gchar *style_class;
+  } actions[] = {
+    {
+      N_("Make _Active"), "config-manager.current",
+      N_("Select this configuration as the active configuration."),
+    },
+    {
+      N_("_Duplicate"), "config-manager.duplicate",
+      N_("Duplicating the configuration allows making changes without modifying this configuration."),
+    },
+    {
+      N_("_Remove"), "config-manager.delete",
+      N_("Removes the configuration and cannot be undone."),
+      "destructive-action",
+    },
+  };
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (ADW_IS_PREFERENCES_GROUP (group));
+  g_assert (IDE_IS_CONFIG (config));
+  g_assert (page_name != NULL && g_str_equal (page_name, ide_config_get_id (config)));
+
+  context = ide_object_get_context (IDE_OBJECT (config));
+  build_system = ide_build_system_from_context (context);
+  workdir = ide_context_ref_workdir (context);
+
+  add_description_row (group, _("Name"), ide_config_get_display_name (config));
+  add_description_row (group, _("Source Directory"), g_file_peek_path (workdir));
+  add_description_row (group, _("Build System"), ide_build_system_get_display_name (build_system));
+  /* Translators: "Install" is a noun here */
+  add_entry_row (group, _("Install Prefix"), config, "prefix");
+  /* Translators: "Configure" is a noun here */
+  add_entry_row (group, _("Configure Options"), config, "config-opts");
+  /* Translators: "Run" is a noun here, this string is analogous to "Execution Options" */
+  add_entry_row (group, _("Run Options"), config, "run-opts");
+
+  config_manager = ide_config_manager_from_context (context);
+  gtk_widget_insert_action_group (GTK_WIDGET (group),
+                                  "config-manager",
+                                  G_ACTION_GROUP (config_manager));
+
+  /* actions button box */
+  box = g_object_new (GTK_TYPE_BOX,
+                      "homogeneous", TRUE,
+                      "margin-top", 12,
+                      "spacing", 12,
+                      "visible", TRUE,
+                      NULL);
+  for (guint i = 0; i < G_N_ELEMENTS (actions); i++)
+    {
+      GtkWidget *button;
+
+      button = g_object_new (GTK_TYPE_BUTTON,
+                             "visible", TRUE,
+                             "action-name", actions[i].action,
+                             "action-target", g_variant_new_string (ide_config_get_id (config)),
+                             "label", g_dgettext (GETTEXT_PACKAGE, actions[i].label),
+                             "tooltip-text", g_dgettext (GETTEXT_PACKAGE, actions[i].tooltip),
+                             "use-underline", TRUE,
+                             NULL);
+      if (actions[i].style_class)
+        gtk_widget_add_css_class (button, actions[i].style_class);
+      gtk_box_append (GTK_BOX (box), button);
+    }
+
+  adw_preferences_group_add (group, box);
+}
+
+static void
+notify_toolchain_id (IdeConfig  *config,
+                     GParamSpec *pspec,
+                     GtkImage   *image)
+{
+  const gchar *toolchain_id;
+  const gchar *current;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_CONFIG (config));
+  g_assert (GTK_IS_IMAGE (image));
+
+  toolchain_id = ide_config_get_toolchain_id (config);
+  current = g_object_get_data (G_OBJECT (image), "TOOLCHAIN_ID");
+
+  gtk_widget_set_visible (GTK_WIDGET (image), ide_str_equal0 (toolchain_id, current));
+}
+
+static GtkWidget *
+create_toolchain_row (gpointer item,
+                      gpointer user_data)
+{
+  IdeToolchain *toolchain = item;
+  IdeConfig *config = user_data;
+  const gchar *toolchain_id;
+  GtkWidget *image;
+  GtkWidget *row;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TOOLCHAIN (toolchain));
+  g_assert (IDE_IS_CONFIG (config));
+
+  toolchain_id = ide_toolchain_get_id (toolchain);
+
+  row = g_object_new (ADW_TYPE_ACTION_ROW,
+                      "title", ide_toolchain_get_display_name (toolchain),
+                      NULL);
+
+  g_object_set_data_full (G_OBJECT (row), "TOOLCHAIN_ID", g_strdup (toolchain_id), g_free);
+
+  image = g_object_new (GTK_TYPE_IMAGE,
+                        "icon-name", "object-select-symbolic",
+                        "valign", GTK_ALIGN_CENTER,
+                        NULL);
+  g_object_set_data_full (G_OBJECT (image), "TOOLCHAIN_ID", g_strdup (toolchain_id), g_free);
+  adw_action_row_add_suffix (ADW_ACTION_ROW (row), image);
+
+  g_signal_connect_object (config,
+                           "notify::toolchain-id",
+                           G_CALLBACK (notify_toolchain_id),
+                           image,
+                           0);
+
+  notify_toolchain_id (config, NULL, GTK_IMAGE (image));
+
+  return row;
+}
+
+static void
+on_toolchain_row_activated_cb (GtkListBox    *list_box,
+                               GtkListBoxRow *row,
+                               IdeConfig     *config)
+{
+  const gchar *toolchain_id;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GTK_IS_LIST_BOX (list_box));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
+  g_assert (IDE_IS_CONFIG (config));
+
+  if ((toolchain_id = g_object_get_data (G_OBJECT (row), "TOOLCHAIN_ID")))
+    ide_config_set_toolchain_id (config, toolchain_id);
+
+  gtk_list_box_unselect_all (list_box);
+}
+
+static void
+create_toolchain_widgetry (const char                   *page_name,
+                           const IdePreferenceItemEntry *entry,
+                           AdwPreferencesGroup          *group,
+                           gpointer                      user_data)
+{
+  IdeToolchainManager *toolchain_manager;
+  IdeConfig *config = user_data;
+  GtkListBox *listbox;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (ADW_IS_PREFERENCES_GROUP (group));
+  g_assert (IDE_IS_CONFIG (config));
+  g_assert (page_name != NULL && g_str_equal (page_name, ide_config_get_id (config)));
+
+  context = ide_object_get_context (IDE_OBJECT (config));
+  toolchain_manager = ide_toolchain_manager_from_context (context);
+
+  listbox = GTK_LIST_BOX (gtk_list_box_new ());
+  gtk_widget_add_css_class (GTK_WIDGET (listbox), "boxed-list");
+  g_signal_connect_object (listbox,
+                           "row-activated",
+                           G_CALLBACK (on_toolchain_row_activated_cb),
+                           config,
+                           0);
+
+  gtk_list_box_bind_model (listbox,
+                           G_LIST_MODEL (toolchain_manager),
+                           create_toolchain_row,
+                           g_object_ref (config),
+                           g_object_unref);
+
+  adw_preferences_group_add (group, GTK_WIDGET (listbox));
+}
+
+static void
+create_runtime_widgetry (const char                   *page_name,
+                         const IdePreferenceItemEntry *entry,
+                         AdwPreferencesGroup          *group,
+                         gpointer                      user_data)
+{
+  g_autoptr(GbpBuilduiRuntimeCategories) filter = NULL;
+  IdeRuntimeManager *runtime_manager;
+  IdeContext *context;
+  IdeConfig *config = user_data;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (ADW_IS_PREFERENCES_GROUP (group));
+  g_assert (IDE_IS_CONFIG (config));
+  g_assert (page_name != NULL && g_str_equal (page_name, ide_config_get_id (config)));
+
+  context = ide_object_get_context (IDE_OBJECT (config));
+  runtime_manager = ide_runtime_manager_from_context (context);
+
+  filter = gbp_buildui_runtime_categories_new (runtime_manager, NULL);
+
+  // TODO
+}
+
+static void
+gbp_buildui_preferences_addin_load (IdePreferencesAddin  *addin,
+                                    IdePreferencesWindow *window,
+                                    IdeContext           *context)
+{
+  GbpBuilduiPreferencesAddin *self = (GbpBuilduiPreferencesAddin *)addin;
+  IdePreferencePageEntry *pages;
+  IdeConfigManager *config_manager;
+  guint n_configs;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_BUILDUI_PREFERENCES_ADDIN (self));
+  g_assert (IDE_IS_PREFERENCES_WINDOW (window));
+  g_assert (!context || IDE_IS_CONTEXT (context));
+  g_assert (ide_preferences_window_get_mode (window) == IDE_PREFERENCES_MODE_PROJECT);
+
+  ide_preferences_window_add_groups (window,
+                                     overview_groups,
+                                     G_N_ELEMENTS (overview_groups),
+                                     NULL);
+  ide_preferences_window_add_items (window,
+                                    overview_items,
+                                    G_N_ELEMENTS (overview_items),
+                                    g_object_ref (context),
+                                    g_object_unref);
+
+  config_manager = ide_config_manager_from_context (context);
+  n_configs = g_list_model_get_n_items (G_LIST_MODEL (config_manager));
+  pages = g_new0 (IdePreferencePageEntry, n_configs);
+  for (guint i = 0; i < n_configs; i++)
+    {
+      IdePreferencePageEntry *page;
+      g_autoptr(IdeConfig) config = NULL;
+
+      page = &pages[i];
+      config = g_list_model_get_item (G_LIST_MODEL (config_manager), i);
+
+      page->parent = "build";
+      page->section = NULL;
+      page->name = ide_config_get_id (config);
+      page->icon_name = NULL;
+      page->title = ide_config_get_display_name (config);
+    }
+
+  ide_preferences_window_add_pages (window, pages, n_configs, NULL);
+
+  for (guint i = 0; i < n_configs; i++)
+    {
+      g_autoptr(IdeConfig) config = g_list_model_get_item (G_LIST_MODEL (config_manager), i);
+      const char *page = ide_config_get_id (config);
+
+      const IdePreferenceGroupEntry groups[] = {
+        { page, "general",     0, N_("General") },
+        { page, "toolchain", 100, N_("Build Toolchain") },
+        { page, "runtime",   200, N_("Application Runtime") },
+      };
+
+      const IdePreferenceItemEntry items[] = {
+        { page, "general",   "general",     0, create_general_widgetry },
+        { page, "toolchain", "toolchain", 100, create_toolchain_widgetry },
+        { page, "runtime",   "runtime",   200, create_runtime_widgetry },
+      };
+
+      ide_preferences_window_add_groups (window, groups, G_N_ELEMENTS (groups), NULL);
+      ide_preferences_window_add_items (window, items, G_N_ELEMENTS (items), config, NULL);
+    }
+
+  IDE_EXIT;
+}
+
+static void
+preferences_addin_init (IdePreferencesAddinInterface *iface)
+{
+  iface->load = gbp_buildui_preferences_addin_load;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpBuilduiPreferencesAddin, gbp_buildui_preferences_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_PREFERENCES_ADDIN, preferences_addin_init))
+
+static void
+gbp_buildui_preferences_addin_class_init (GbpBuilduiPreferencesAddinClass *klass)
+{
+}
+
+static void
+gbp_buildui_preferences_addin_init (GbpBuilduiPreferencesAddin *self)
+{
+}
diff --git a/src/plugins/buildui/gbp-buildui-preferences-addin.h 
b/src/plugins/buildui/gbp-buildui-preferences-addin.h
new file mode 100644
index 000000000..40126c91b
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-preferences-addin.h
@@ -0,0 +1,31 @@
+/* gbp-buildui-preferences-addin.h
+ *
+ * Copyright 2022 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *           2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-gui.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_PREFERENCES_ADDIN (gbp_buildui_preferences_addin_get_type())
+G_DECLARE_FINAL_TYPE (GbpBuilduiPreferencesAddin, gbp_buildui_preferences_addin, GBP, 
BUILDUI_PREFERENCES_ADDIN, GObject)
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-runnables-dialog.c 
b/src/plugins/buildui/gbp-buildui-runnables-dialog.c
new file mode 100644
index 000000000..28ba6af1b
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-runnables-dialog.c
@@ -0,0 +1,315 @@
+/*
+ * gbp-buildui-runnables-dialog.c
+ *
+ * Copyright 2022 Christian Hergert <>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-runnables-dialog"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+
+#include <libide-gtk.h>
+#include <libide-gui.h>
+
+#include "gbp-buildui-runnables-dialog.h"
+
+struct _GbpBuilduiRunnablesDialog
+{
+  AdwWindow           parent_instance;
+  IdeContext         *context;
+  GtkListBox         *list_box;
+  AdwPreferencesPage *page;
+  GtkStack           *stack;
+  guint               busy : 1;
+};
+
+G_DEFINE_FINAL_TYPE (GbpBuilduiRunnablesDialog, gbp_buildui_runnables_dialog, ADW_TYPE_WINDOW)
+
+enum {
+  PROP_0,
+  PROP_CONTEXT,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static GtkWidget *
+create_run_command_row (gpointer item,
+                        gpointer user_data)
+{
+  IdeRunCommand *run_command = item;
+  g_autoptr(GVariant) idv = NULL;
+  g_autoptr(GString) subtitle = NULL;
+  const char * const *argv;
+  AdwActionRow *row;
+  const char *id;
+  GtkWidget *check;
+  GtkWidget *label = NULL;
+
+  g_assert (IDE_IS_RUN_COMMAND (run_command));
+
+  id = ide_run_command_get_id (run_command);
+  idv = g_variant_take_ref (g_variant_new_string (id ? id : ""));
+  argv = ide_run_command_get_argv (run_command);
+
+  if (argv != NULL)
+    {
+      subtitle = g_string_new ("<tt>");
+
+      for (guint i = 0; argv[i]; i++)
+        {
+          const char *arg = argv[i];
+          g_autofree char *quote = NULL;
+          g_autofree char *arg_escaped = NULL;
+
+          if (i > 0)
+            g_string_append_c (subtitle, ' ');
+
+          /* NOTE: Params can be file-system encoding, but everywhere we run
+           * that is UTF-8. May need to adjust should that change.
+           */
+          for (const char *c = arg; *c; c = g_utf8_next_char (c))
+            {
+              if (*c == ' ' || *c == '"' || *c == '\'')
+                {
+                  quote = g_shell_quote (arg);
+                  break;
+                }
+            }
+
+          if (quote != NULL)
+            arg_escaped = g_markup_escape_text (quote, -1);
+          else
+            arg_escaped = g_markup_escape_text (arg, -1);
+
+          g_string_append (subtitle, arg_escaped);
+        }
+
+      g_string_append (subtitle, "</tt>");
+    }
+
+  if (ide_run_command_get_kind (run_command) == IDE_RUN_COMMAND_KIND_TEST)
+    label = g_object_new (GTK_TYPE_LABEL,
+                          "css-name", "button",
+                          "css-classes", IDE_STRV_INIT ("pill", "small"),
+                          "label", _("Test"),
+                          "valign", GTK_ALIGN_CENTER,
+                          NULL);
+
+  check = g_object_new (GTK_TYPE_CHECK_BUTTON,
+                        "action-name", "run-manager.default-run-command",
+                        "css-classes", IDE_STRV_INIT ("checkimage"),
+                        "action-target", idv,
+                        "valign", GTK_ALIGN_CENTER,
+                        "can-focus", FALSE,
+                        NULL);
+  row = g_object_new (ADW_TYPE_ACTION_ROW,
+                      "title", ide_run_command_get_display_name (item),
+                      "subtitle", subtitle ? subtitle->str : NULL,
+                      "activatable-widget", check,
+                      NULL);
+
+  if (label != NULL)
+    adw_action_row_add_suffix (row, label);
+
+  adw_action_row_add_suffix (row, check);
+
+  return GTK_WIDGET (row);
+}
+
+static void
+gbp_buildui_runnables_dialog_list_commands_cb (GObject      *object,
+                                               GAsyncResult *result,
+                                               gpointer      user_data)
+{
+  IdeRunManager *run_manager = (IdeRunManager *)object;
+  g_autoptr(GbpBuilduiRunnablesDialog) self = user_data;
+  g_autoptr(GListModel) model = NULL;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_RUN_MANAGER (run_manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (GBP_IS_BUILDUI_RUNNABLES_DIALOG (self));
+
+  gtk_stack_set_visible_child_name (self->stack, "list");
+
+  if (!(model = ide_run_manager_list_commands_finish (run_manager, result, &error)))
+    {
+      if (!ide_error_ignore (error))
+        ide_object_warning (run_manager,
+                            /* translators: %s is replaced with the error message */
+                            _("Failed to list run commands: %s"),
+                            error->message);
+      IDE_EXIT;
+    }
+
+  gtk_list_box_bind_model (self->list_box, model, create_run_command_row, NULL, NULL);
+
+  IDE_EXIT;
+}
+
+static void
+new_run_command_action (GtkWidget  *widget,
+                        const char *action_name,
+                        GVariant   *param)
+{
+  GbpBuilduiRunnablesDialog *self = (GbpBuilduiRunnablesDialog *)widget;
+  IdeWorkspace *workspace;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_RUNNABLES_DIALOG (self));
+
+  workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+  gtk_widget_activate_action (GTK_WIDGET (workspace),
+                              "workbench.configure-page",
+                              "s", "commands");
+  gtk_window_destroy (GTK_WINDOW (self));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_runnables_dialog_realize (GtkWidget *widget)
+{
+  GbpBuilduiRunnablesDialog *self = (GbpBuilduiRunnablesDialog *)widget;
+  IdeRunManager *run_manager;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_RUNNABLES_DIALOG (self));
+  g_assert (IDE_IS_CONTEXT (self->context));
+
+  GTK_WIDGET_CLASS (gbp_buildui_runnables_dialog_parent_class)->realize (widget);
+
+  gtk_stack_set_visible_child_name (self->stack, "loading");
+
+  run_manager = ide_run_manager_from_context (self->context);
+  gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                  "run-manager",
+                                  G_ACTION_GROUP (run_manager));
+  ide_run_manager_list_commands_async (run_manager,
+                                       NULL,
+                                       gbp_buildui_runnables_dialog_list_commands_cb,
+                                       g_object_ref (self));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_runnables_dialog_dispose (GObject *object)
+{
+  GbpBuilduiRunnablesDialog *self = (GbpBuilduiRunnablesDialog *)object;
+
+  g_clear_object (&self->context);
+
+  G_OBJECT_CLASS (gbp_buildui_runnables_dialog_parent_class)->dispose (object);
+}
+
+static void
+gbp_buildui_runnables_dialog_get_property (GObject    *object,
+                                           guint       prop_id,
+                                           GValue     *value,
+                                           GParamSpec *pspec)
+{
+  GbpBuilduiRunnablesDialog *self = GBP_BUILDUI_RUNNABLES_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTEXT:
+      g_value_set_object (value, self->context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_runnables_dialog_set_property (GObject      *object,
+                                           guint         prop_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec)
+{
+  GbpBuilduiRunnablesDialog *self = GBP_BUILDUI_RUNNABLES_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTEXT:
+      self->context = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_runnables_dialog_class_init (GbpBuilduiRunnablesDialogClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = gbp_buildui_runnables_dialog_dispose;
+  object_class->get_property = gbp_buildui_runnables_dialog_get_property;
+  object_class->set_property = gbp_buildui_runnables_dialog_set_property;
+
+  widget_class->realize = gbp_buildui_runnables_dialog_realize;
+
+  properties [PROP_CONTEXT] =
+    g_param_spec_object ("context", NULL, NULL,
+                         IDE_TYPE_CONTEXT,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_install_action (widget_class, "run-command.new", NULL, new_run_command_action);
+
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-runnables-dialog.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiRunnablesDialog, list_box);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiRunnablesDialog, page);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiRunnablesDialog, stack);
+
+  g_type_ensure (IDE_TYPE_ENUM_OBJECT);
+}
+
+static void
+gbp_buildui_runnables_dialog_init (GbpBuilduiRunnablesDialog *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+#ifdef DEVELOPMENT_BUILD
+  gtk_widget_add_css_class (GTK_WIDGET (self), "devel");
+#endif
+
+  for (GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self->page));
+       child != NULL;
+       child = gtk_widget_get_next_sibling (child))
+    {
+      if (GTK_IS_SCROLLED_WINDOW (child))
+        gtk_widget_add_css_class (child, "shadow-when-scroll");
+    }
+}
diff --git a/src/plugins/buildui/gbp-buildui-config-surface.h 
b/src/plugins/buildui/gbp-buildui-runnables-dialog.h
similarity index 62%
rename from src/plugins/buildui/gbp-buildui-config-surface.h
rename to src/plugins/buildui/gbp-buildui-runnables-dialog.h
index ee13c8aa8..1c3b9b69e 100644
--- a/src/plugins/buildui/gbp-buildui-config-surface.h
+++ b/src/plugins/buildui/gbp-buildui-runnables-dialog.h
@@ -1,6 +1,6 @@
-/* gbp-buildui-config-surface.h
+/* gbp-buildui-runnables-dialog.h
  *
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 Christian Hergert <chergert redhat com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,16 +20,16 @@
 
 #pragma once
 
+#include <adwaita.h>
+
 #include <libide-foundry.h>
-#include <libide-gui.h>
 
 G_BEGIN_DECLS
 
-#define GBP_TYPE_BUILDUI_CONFIG_SURFACE (gbp_buildui_config_surface_get_type())
+#define GBP_TYPE_BUILDUI_RUNNABLES_DIALOG (gbp_buildui_runnables_dialog_get_type())
 
-G_DECLARE_FINAL_TYPE (GbpBuilduiConfigSurface, gbp_buildui_config_surface, GBP, BUILDUI_CONFIG_SURFACE, 
IdeSurface)
+G_DECLARE_FINAL_TYPE (GbpBuilduiRunnablesDialog, gbp_buildui_runnables_dialog, GBP, 
BUILDUI_RUNNABLES_DIALOG, AdwWindow)
 
-void gbp_buildui_config_surface_set_config (GbpBuilduiConfigSurface *self,
-                                            IdeConfig        *config);
+GtkWidget *gbp_buildui_runnables_dialog_new (IdeContext *context);
 
 G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-runnables-dialog.ui 
b/src/plugins/buildui/gbp-buildui-runnables-dialog.ui
new file mode 100644
index 000000000..ceb20e5a9
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-runnables-dialog.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpBuilduiRunnablesDialog" parent="AdwWindow">
+    <property name="default-width">700</property>
+    <property name="default-height">550</property>
+    <child type="content">
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="AdwHeaderBar">
+            <style>
+              <class name="flat"/>
+            </style>
+            <child type="title">
+              <object class="AdwWindowTitle">
+                <property name="title" translatable="yes">Select Run Command</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="AdwPreferencesPage" id="page">
+            <child>
+              <object class="AdwPreferencesGroup">
+                <property name="title" translatable="yes">Available Run Commands</property>
+                <property name="description" translatable="yes">Some run commands may not be available until 
the project has been configured.</property>
+                <child>
+                  <object class="AdwActionRow">
+                    <property name="title" translatable="yes">Project Default</property>
+                    <property name="subtitle" translatable="yes">This selection allows the build system to 
choose the best default candidate.</property>
+                    <property name="activatable-widget">default_runnable</property>
+                    <child type="suffix">
+                      <object class="GtkCheckButton" id="default_runnable">
+                        <property name="action-name">run-manager.default-run-command</property>
+                        <property name="action-target">''</property>
+                        <style>
+                          <class name="checkimage"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="margin-top">12</property>
+                    <property name="margin-bottom">12</property>
+                    <property name="use-underline">true</property>
+                    <property name="label" translatable="yes">_Custom Command…</property>
+                    <property name="action-name">run-command.new</property>
+                    <property name="halign">end</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkStack" id="stack">
+                    <property name="hhomogeneous">false</property>
+                    <property name="vhomogeneous">false</property>
+                    <child>
+                      <object class="GtkStackPage">
+                        <property name="name">loading</property>
+                        <property name="child">
+                          <object class="GtkListBox">
+                            <property name="margin-top">12</property>
+                            <property name="selection-mode">none</property>
+                            <style>
+                              <class name="boxed-list"/>
+                            </style>
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="icon-name">content-loading-symbolic</property>
+                                <property name="title" translatable="yes">Loading Run Commands</property>
+                                <property name="subtitle" translatable="yes">Your project may require 
building to load run commands</property>
+                              </object>
+                            </child>
+                          </object>
+                        </property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkStackPage">
+                        <property name="name">list</property>
+                        <property name="child">
+                          <object class="GtkListBox" id="list_box">
+                            <property name="margin-top">12</property>
+                            <property name="selection-mode">none</property>
+                            <style>
+                              <class name="boxed-list"/>
+                            </style>
+                          </object>
+                        </property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/buildui/gbp-buildui-runtime-categories.c 
b/src/plugins/buildui/gbp-buildui-runtime-categories.c
index 4bea7cd0a..5f2b9fe58 100644
--- a/src/plugins/buildui/gbp-buildui-runtime-categories.c
+++ b/src/plugins/buildui/gbp-buildui-runtime-categories.c
@@ -35,16 +35,6 @@ struct _GbpBuilduiRuntimeCategories
   IdeRuntimeManager *runtime_manager;
 };
 
-static gboolean
-filter_by_category (GObject *object,
-                    gpointer user_data)
-{
-  const gchar *category = user_data;
-  IdeRuntime *runtime = IDE_RUNTIME (object);
-
-  return ide_str_equal0 (category, ide_runtime_get_category (runtime));
-}
-
 static GType
 gbp_buildui_runtime_categories_get_item_type (GListModel *model)
 {
@@ -224,7 +214,8 @@ gbp_buildui_runtime_categories_create_child_model (GbpBuilduiRuntimeCategories *
 {
   g_autofree gchar *prefix = NULL;
   g_autofree gchar *name = NULL;
-  DzlListModelFilter *filter;
+  GtkFilterListModel *filter_model;
+  GtkStringFilter *filter;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_BUILDUI_RUNTIME_CATEGORIES (self));
@@ -240,12 +231,9 @@ gbp_buildui_runtime_categories_create_child_model (GbpBuilduiRuntimeCategories *
   if (g_str_has_suffix (category, "/"))
     return G_LIST_MODEL (gbp_buildui_runtime_categories_new (self->runtime_manager, prefix));
 
-  filter = dzl_list_model_filter_new (G_LIST_MODEL (self->runtime_manager));
+  filter = gtk_string_filter_new (gtk_property_expression_new (IDE_TYPE_RUNTIME, NULL, "caregory"));
+  filter_model = gtk_filter_list_model_new (G_LIST_MODEL (self->runtime_manager), GTK_FILTER (filter));
   g_object_set_data_full (G_OBJECT (filter), "CATEGORY", g_steal_pointer (&name), g_free);
-  dzl_list_model_filter_set_filter_func (filter,
-                                         filter_by_category,
-                                         g_strdup (prefix),
-                                         g_free);
 
-  return G_LIST_MODEL (g_steal_pointer (&filter));
+  return G_LIST_MODEL (g_steal_pointer (&filter_model));
 }
diff --git a/src/plugins/buildui/gbp-buildui-runtime-row.c b/src/plugins/buildui/gbp-buildui-runtime-row.c
index 2a3774c35..2599ff0b2 100644
--- a/src/plugins/buildui/gbp-buildui-runtime-row.c
+++ b/src/plugins/buildui/gbp-buildui-runtime-row.c
@@ -26,15 +26,14 @@
 
 struct _GbpBuilduiRuntimeRow
 {
-  GtkListBoxRow  parent_instance;
+  AdwActionRow  parent_instance;
 
   gchar         *runtime_id;
 
-  GtkLabel      *label;
   GtkImage      *image;
 };
 
-G_DEFINE_FINAL_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, GTK_TYPE_LIST_BOX_ROW)
+G_DEFINE_FINAL_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, ADW_TYPE_ACTION_ROW)
 
 static void
 gbp_buildui_runtime_row_finalize (GObject *object)
@@ -57,30 +56,11 @@ gbp_buildui_runtime_row_class_init (GbpBuilduiRuntimeRowClass *klass)
 static void
 gbp_buildui_runtime_row_init (GbpBuilduiRuntimeRow *self)
 {
-  GtkWidget *box;
-
-  box = g_object_new (GTK_TYPE_BOX,
-                      "margin", 10,
-                      "orientation", GTK_ORIENTATION_HORIZONTAL,
-                      "spacing", 6,
-                      "visible", TRUE,
-                      NULL);
-  gtk_container_add (GTK_CONTAINER (self), box);
-
-  self->label = g_object_new (GTK_TYPE_LABEL,
-                              "visible", TRUE,
-                              "use-markup", TRUE,
-                              "xalign", 0.0f,
-                              NULL);
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (self->label));
-
   self->image = g_object_new (GTK_TYPE_IMAGE,
-                              "visible", TRUE,
-                              "halign", GTK_ALIGN_START,
-                              "hexpand", TRUE,
+                              "valign", GTK_ALIGN_CENTER,
                               "icon-name", "object-select-symbolic",
                               NULL);
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (self->image));
+  adw_action_row_add_suffix (ADW_ACTION_ROW (self), GTK_WIDGET (self->image));
 }
 
 static void
@@ -97,8 +77,8 @@ notify_config_runtime_id (GbpBuilduiRuntimeRow *self,
 }
 
 GtkWidget *
-gbp_buildui_runtime_row_new (IdeRuntime       *runtime,
-                             IdeConfig *config)
+gbp_buildui_runtime_row_new (IdeRuntime *runtime,
+                             IdeConfig  *config)
 {
   GbpBuilduiRuntimeRow *self;
   gboolean sensitive;
@@ -110,11 +90,10 @@ gbp_buildui_runtime_row_new (IdeRuntime       *runtime,
 
   self = g_object_new (GBP_TYPE_BUILDUI_RUNTIME_ROW,
                        "sensitive", sensitive,
-                       "visible", TRUE,
                        NULL);
   self->runtime_id = g_strdup (ide_runtime_get_id (runtime));
-  gtk_label_set_label (self->label,
-                       ide_runtime_get_display_name (runtime));
+  adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self),
+                                 ide_runtime_get_display_name (runtime));
 
   g_signal_connect_object (config,
                            "notify::runtime-id",
diff --git a/src/plugins/buildui/gbp-buildui-runtime-row.h b/src/plugins/buildui/gbp-buildui-runtime-row.h
index c7dfff99f..c646d3a34 100644
--- a/src/plugins/buildui/gbp-buildui-runtime-row.h
+++ b/src/plugins/buildui/gbp-buildui-runtime-row.h
@@ -20,14 +20,14 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
+#include <adwaita.h>
 #include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
 #define GBP_TYPE_BUILDUI_RUNTIME_ROW (gbp_buildui_runtime_row_get_type())
 
-G_DECLARE_FINAL_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, GBP, BUILDUI_RUNTIME_ROW, GtkListBoxRow)
+G_DECLARE_FINAL_TYPE (GbpBuilduiRuntimeRow, gbp_buildui_runtime_row, GBP, BUILDUI_RUNTIME_ROW, AdwActionRow)
 
 GtkWidget   *gbp_buildui_runtime_row_new    (IdeRuntime           *runtime,
                                              IdeConfig     *config);
diff --git a/src/plugins/buildui/gbp-buildui-stage-row.c b/src/plugins/buildui/gbp-buildui-stage-row.c
index 3e1bcf11d..f6d950d4d 100644
--- a/src/plugins/buildui/gbp-buildui-stage-row.c
+++ b/src/plugins/buildui/gbp-buildui-stage-row.c
@@ -22,8 +22,6 @@
 
 #include "config.h"
 
-#include <dazzle.h>
-
 #include "gbp-buildui-stage-row.h"
 
 struct _GbpBuilduiStageRow
@@ -32,7 +30,7 @@ struct _GbpBuilduiStageRow
 
   IdePipelineStage   *stage;
 
-  DzlBoldingLabel *label;
+  GtkLabel           *label;
 };
 
 enum {
@@ -45,6 +43,20 @@ G_DEFINE_FINAL_TYPE (GbpBuilduiStageRow, gbp_buildui_stage_row, GTK_TYPE_LIST_BO
 
 static GParamSpec *properties [N_PROPS];
 
+static void
+gbp_buildui_stage_row_notify_active (GbpBuilduiStageRow *row,
+                                     GParamSpec         *pspec,
+                                     IdePipelineStage   *stage)
+{
+  g_assert (GBP_IS_BUILDUI_STAGE_ROW (row));
+  g_assert (IDE_IS_PIPELINE_STAGE (stage));
+
+  if (ide_pipeline_stage_get_active (stage))
+    gtk_widget_add_css_class (GTK_WIDGET (row->label), "heading");
+  else
+    gtk_widget_remove_css_class (GTK_WIDGET (row->label), "heading");
+}
+
 static void
 gbp_buildui_stage_row_notify_completed (GbpBuilduiStageRow *row,
                                       GParamSpec       *pspec,
@@ -54,9 +66,9 @@ gbp_buildui_stage_row_notify_completed (GbpBuilduiStageRow *row,
   g_assert (IDE_IS_PIPELINE_STAGE (stage));
 
   if (ide_pipeline_stage_get_completed (stage))
-    dzl_gtk_widget_add_style_class (GTK_WIDGET (row->label), "dim-label");
+    gtk_widget_add_css_class (GTK_WIDGET (row->label), "dim-label");
   else
-    dzl_gtk_widget_remove_style_class (GTK_WIDGET (row->label), "dim-label");
+    gtk_widget_remove_css_class (GTK_WIDGET (row->label), "dim-label");
 }
 
 static void
@@ -75,7 +87,7 @@ gbp_buildui_stage_row_set_stage (GbpBuilduiStageRow *self,
   if (name == NULL)
     name = G_OBJECT_TYPE_NAME (stage);
 
-  gtk_label_set_label (GTK_LABEL (self->label), name);
+  gtk_label_set_label (self->label, name);
 
   g_signal_connect_object (stage,
                            "notify::completed",
@@ -83,20 +95,28 @@ gbp_buildui_stage_row_set_stage (GbpBuilduiStageRow *self,
                            self,
                            G_CONNECT_SWAPPED);
 
+  g_signal_connect_object (stage,
+                           "notify::active",
+                           G_CALLBACK (gbp_buildui_stage_row_notify_active),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   g_object_bind_property (stage, "disabled", self, "sensitive", G_BINDING_DEFAULT);
+#if 0
   g_object_bind_property (stage, "active", self->label, "bold", G_BINDING_DEFAULT);
+#endif
 
   gbp_buildui_stage_row_notify_completed (self, NULL, stage);
 }
 
 static void
-gbp_buildui_stage_row_destroy (GtkWidget *widget)
+gbp_buildui_stage_row_dispose (GObject *object)
 {
-  GbpBuilduiStageRow *self = (GbpBuilduiStageRow *)widget;
+  GbpBuilduiStageRow *self = (GbpBuilduiStageRow *)object;
 
   g_clear_object (&self->stage);
 
-  GTK_WIDGET_CLASS (gbp_buildui_stage_row_parent_class)->destroy (widget);
+  G_OBJECT_CLASS (gbp_buildui_stage_row_parent_class)->dispose (object);
 }
 
 static void
@@ -143,11 +163,10 @@ gbp_buildui_stage_row_class_init (GbpBuilduiStageRowClass *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
+  object_class->dispose = gbp_buildui_stage_row_dispose;
   object_class->get_property = gbp_buildui_stage_row_get_property;
   object_class->set_property = gbp_buildui_stage_row_set_property;
 
-  widget_class->destroy = gbp_buildui_stage_row_destroy;
-
   properties [PROP_STAGE] =
     g_param_spec_object ("stage",
                          "Stage",
@@ -175,7 +194,6 @@ gbp_buildui_stage_row_new (IdePipelineStage *stage)
 
   return g_object_new (GBP_TYPE_BUILDUI_STAGE_ROW,
                        "stage", stage,
-                       "visible", TRUE,
                        NULL);
 }
 
@@ -186,8 +204,6 @@ gbp_buildui_stage_row_new (IdePipelineStage *stage)
  * Gets the stage for the row.
  *
  * Returns: (transfer none): an #IdePipelineStage
- *
- * Since: 3.32
  */
 IdePipelineStage *
 gbp_buildui_stage_row_get_stage (GbpBuilduiStageRow *self)
diff --git a/src/plugins/buildui/gbp-buildui-stage-row.ui b/src/plugins/buildui/gbp-buildui-stage-row.ui
index 9eb96f579..1408292fa 100644
--- a/src/plugins/buildui/gbp-buildui-stage-row.ui
+++ b/src/plugins/buildui/gbp-buildui-stage-row.ui
@@ -3,11 +3,13 @@
   <template class="GbpBuilduiStageRow" parent="GtkListBoxRow">
     <child>
       <object class="GtkBox">
-        <property name="visible">true</property>
         <property name="orientation">horizontal</property>
         <child>
-          <object class="DzlBoldingLabel" id="label">
-            <property name="visible">true</property>
+          <object class="GtkLabel" id="label">
+            <property name="margin-top">6</property>
+            <property name="margin-bottom">6</property>
+            <property name="margin-start">9</property>
+            <property name="margin-bottom">9</property>
             <property name="xalign">0.0</property>
           </object>
         </child>
diff --git a/src/plugins/buildui/gbp-buildui-status-indicator.c 
b/src/plugins/buildui/gbp-buildui-status-indicator.c
new file mode 100644
index 000000000..707994ab8
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-indicator.c
@@ -0,0 +1,104 @@
+/* gbp-buildui-status-indicator.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-status-indicator"
+
+#include "config.h"
+
+#include <libide-foundry.h>
+
+#include "gbp-buildui-status-indicator.h"
+
+struct _GbpBuilduiStatusIndicator
+{
+  GtkWidget parent_instance;
+
+  GtkWidget *box;
+  GtkWidget *error_label;
+  GtkWidget *warning_label;
+};
+
+G_DEFINE_FINAL_TYPE (GbpBuilduiStatusIndicator, gbp_buildui_status_indicator, GTK_TYPE_WIDGET)
+
+static void
+gbp_buildui_status_indicator_dispose (GObject *object)
+{
+  GbpBuilduiStatusIndicator *self = (GbpBuilduiStatusIndicator *)object;
+
+  g_clear_pointer (&self->box, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (gbp_buildui_status_indicator_parent_class)->dispose (object);
+}
+
+static void
+gbp_buildui_status_indicator_class_init (GbpBuilduiStatusIndicatorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = gbp_buildui_status_indicator_dispose;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-status-indicator.ui");
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusIndicator, box);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusIndicator, error_label);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusIndicator, warning_label);
+}
+
+static void
+gbp_buildui_status_indicator_init (GbpBuilduiStatusIndicator *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+gbp_buildui_status_indicator_connect (GbpBuilduiStatusIndicator *self,
+                                      IdeContext                *context)
+{
+  IdeBuildManager *build_manager;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_INDICATOR (self));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  build_manager = ide_build_manager_from_context (context);
+
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  g_object_bind_property (build_manager, "error-count", self->error_label, "label", G_BINDING_SYNC_CREATE);
+  g_object_bind_property (build_manager, "warning-count", self->warning_label, "label", 
G_BINDING_SYNC_CREATE);
+
+  IDE_EXIT;
+}
+
+GbpBuilduiStatusIndicator *
+gbp_buildui_status_indicator_new (IdeContext *context)
+{
+  GbpBuilduiStatusIndicator *self;
+
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (ide_context_has_project (context), NULL);
+
+  self = g_object_new (GBP_TYPE_BUILDUI_STATUS_INDICATOR, NULL);
+  gbp_buildui_status_indicator_connect (self, context);
+
+  return self;
+}
diff --git a/src/plugins/buildui/gbp-buildui-status-indicator.h 
b/src/plugins/buildui/gbp-buildui-status-indicator.h
new file mode 100644
index 000000000..4217d94ff
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-indicator.h
@@ -0,0 +1,35 @@
+/* gbp-buildui-status-indicator.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_STATUS_INDICATOR (gbp_buildui_status_indicator_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiStatusIndicator, gbp_buildui_status_indicator, GBP, 
BUILDUI_STATUS_INDICATOR, GtkWidget)
+
+GbpBuilduiStatusIndicator *gbp_buildui_status_indicator_new (IdeContext *context);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-status-indicator.ui 
b/src/plugins/buildui/gbp-buildui-status-indicator.ui
new file mode 100644
index 000000000..58d942aa0
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-indicator.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpBuilduiStatusIndicator" parent="GtkWidget">
+    <child>
+      <object class="GtkBox" id="box">
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkBox">
+            <property name="spacing">3</property>
+            <child>
+              <object class="GtkImage">
+                <property name="icon-name">dialog-error-symbolic</property>
+                <property name="pixel-size">12</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkLabel" id="error_label">
+                <property name="label">0</property>
+                <attributes>
+                  <attribute name="font-features" value="tnum"/>
+                </attributes>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="spacing">3</property>
+            <child>
+              <object class="GtkImage">
+                <property name="icon-name">dialog-warning-symbolic</property>
+                <property name="pixel-size">12</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkLabel" id="warning_label">
+                <property name="label">0</property>
+                <attributes>
+                  <attribute name="font-features" value="tnum"/>
+                </attributes>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/buildui/gbp-buildui-status-popover-row.ui 
b/src/plugins/buildui/gbp-buildui-status-popover-row.ui
new file mode 100644
index 000000000..ca4af3f55
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-popover-row.ui
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <property name="margin-top">3</property>
+        <property name="margin-bottom">3</property>
+        <property name="margin-start">6</property>
+        <property name="margin-end">6</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="halign">start</property>
+            <property name="hexpand">true</property>
+            <property name="ellipsize">start</property>
+            <style>
+              <class name="dim-label"/>
+            </style>
+            <binding name="label">
+              <lookup name="title" type="IdeLocation">
+                <lookup name="location" type="IdeDiagnostic">
+                  <lookup name="item">GtkListItem</lookup>
+                </lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="halign">start</property>
+            <property name="hexpand">true</property>
+            <property name="wrap">true</property>
+            <binding name="label">
+              <lookup name="text" type="IdeDiagnostic">
+                <lookup name="item">GtkListItem</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+      </object>
+    </property>
+  </template>
+</interface>
+
diff --git a/src/plugins/buildui/gbp-buildui-status-popover.c 
b/src/plugins/buildui/gbp-buildui-status-popover.c
new file mode 100644
index 000000000..160548fd0
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-popover.c
@@ -0,0 +1,321 @@
+/* gbp-buildui-status-popover.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-status-popover"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-editor.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+
+#include "gbp-buildui-status-popover.h"
+
+struct _GbpBuilduiStatusPopover
+{
+  GtkPopover       parent_instance;
+
+  /* Owned references */
+  IdeSignalGroup  *pipeline_signals;
+  GHashTable      *deduplicator;
+
+  /* Template references */
+  GListStore      *diagnostics;
+  GtkStack        *stack;
+  GtkCustomFilter *error_filter;
+  GtkCustomFilter *warning_filter;
+  GtkStackPage    *errors;
+  GListModel      *errors_model;
+  GtkStackPage    *warnings;
+  GListModel      *warnings_model;
+};
+
+G_DEFINE_FINAL_TYPE (GbpBuilduiStatusPopover, gbp_buildui_status_popover, GTK_TYPE_POPOVER)
+
+static gboolean
+warnings_title_cb (GBinding     *binding,
+                   const GValue *from_value,
+                   GValue       *to_value,
+                   gpointer      user_data)
+{
+  guint n_items = g_value_get_uint (from_value);
+  g_value_take_string (to_value,
+                       /* translators: %u is replaced with the number of warnings */
+                       g_strdup_printf (_("Warnings (%u)"), n_items));
+  return TRUE;
+}
+
+static gboolean
+errors_title_cb (GBinding     *binding,
+                 const GValue *from_value,
+                 GValue       *to_value,
+                 gpointer      user_data)
+{
+  guint n_items = g_value_get_uint (from_value);
+  g_value_take_string (to_value,
+                       /* translators: %u is replaced with the number of errors */
+                       g_strdup_printf (_("Errors (%u)"), n_items));
+  return TRUE;
+}
+
+static void
+gbp_buildui_status_popover_clear (GbpBuilduiStatusPopover *self)
+{
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+
+  if (self->diagnostics != NULL)
+    g_list_store_remove_all (self->diagnostics);
+
+  if (self->deduplicator != NULL)
+    g_hash_table_remove_all (self->deduplicator);
+}
+
+static void
+gbp_buildui_status_popover_add_diagnsotic (GbpBuilduiStatusPopover *self,
+                                           IdeDiagnostic           *diagnostic,
+                                           IdePipeline             *pipeline)
+{
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_assert (IDE_IS_DIAGNOSTIC (diagnostic));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+
+  if (g_hash_table_contains (self->deduplicator, diagnostic))
+    return;
+
+  g_hash_table_insert (self->deduplicator, g_object_ref (diagnostic), NULL);
+  g_list_store_insert_sorted (self->diagnostics,
+                              diagnostic,
+                              (GCompareDataFunc)ide_diagnostic_compare,
+                              NULL);
+}
+
+static void
+gbp_buildui_status_popover_bind_pipeline (GbpBuilduiStatusPopover *self,
+                                          IdePipeline             *pipeline,
+                                          IdeSignalGroup          *signal_group)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+  g_assert (IDE_IS_SIGNAL_GROUP (signal_group));
+
+  gbp_buildui_status_popover_clear (self);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_status_popover_unbind_pipeline (GbpBuilduiStatusPopover *self,
+                                            IdeSignalGroup          *signal_group)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_assert (IDE_IS_SIGNAL_GROUP (signal_group));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_status_popover_activate_cb (GbpBuilduiStatusPopover *self,
+                                        guint                    item_position,
+                                        GtkListView             *list_view)
+{
+  g_autoptr(IdePanelPosition) position = NULL;
+  g_autoptr(IdeDiagnostic) diagnostic = NULL;
+  IdeWorkspace *workspace;
+  IdeLocation *location;
+  GListModel *model;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_assert (GTK_IS_LIST_VIEW (list_view));
+
+  if (!(model = G_LIST_MODEL (gtk_list_view_get_model (list_view))) ||
+      !(diagnostic = g_list_model_get_item (model, item_position)) ||
+      !IDE_IS_DIAGNOSTIC (diagnostic) ||
+      !(location = ide_diagnostic_get_location (diagnostic)))
+    IDE_EXIT;
+
+  workspace = ide_widget_get_workspace (GTK_WIDGET (self));
+  position = ide_panel_position_new ();
+  ide_editor_focus_location (workspace, position, location);
+
+  gtk_popover_popdown (GTK_POPOVER (self));
+
+  IDE_EXIT;
+}
+
+static gboolean
+is_warning (gpointer data,
+            gpointer user_data)
+{
+  return ide_diagnostic_get_severity (data) == IDE_DIAGNOSTIC_WARNING;
+}
+
+static gboolean
+is_error (gpointer data,
+          gpointer user_data)
+{
+  return ide_diagnostic_get_severity (data) == IDE_DIAGNOSTIC_ERROR;
+}
+
+static void
+gbp_buildui_status_popover_closed (GtkPopover *popover)
+{
+  GbpBuilduiStatusPopover *self = (GbpBuilduiStatusPopover *)popover;
+  IdeWorkspace *workspace;
+  IdePage *page;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+
+  if ((workspace = ide_widget_get_workspace (GTK_WIDGET (self))) &&
+      (page = ide_workspace_get_most_recent_page (workspace)))
+    gtk_widget_grab_focus (GTK_WIDGET (page));
+}
+
+static void
+gbp_buildui_status_popover_dispose (GObject *object)
+{
+  GbpBuilduiStatusPopover *self = (GbpBuilduiStatusPopover *)object;
+
+  g_clear_object (&self->pipeline_signals);
+  g_clear_pointer (&self->deduplicator, g_hash_table_unref);
+
+  G_OBJECT_CLASS (gbp_buildui_status_popover_parent_class)->dispose (object);
+}
+
+static void
+gbp_buildui_status_popover_class_init (GbpBuilduiStatusPopoverClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkPopoverClass *popover_class = GTK_POPOVER_CLASS (klass);
+
+  object_class->dispose = gbp_buildui_status_popover_dispose;
+
+  popover_class->closed = gbp_buildui_status_popover_closed;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-status-popover.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, diagnostics);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, error_filter);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, errors);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, errors_model);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, stack);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, warning_filter);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, warnings);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiStatusPopover, warnings_model);
+  gtk_widget_class_bind_template_callback (widget_class, gbp_buildui_status_popover_activate_cb);
+
+  g_type_ensure (IDE_TYPE_DIAGNOSTIC);
+  g_type_ensure (IDE_TYPE_LOCATION);
+}
+
+static void
+gbp_buildui_status_popover_init (GbpBuilduiStatusPopover *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  gtk_custom_filter_set_filter_func (self->warning_filter, is_warning, NULL, NULL);
+  gtk_custom_filter_set_filter_func (self->error_filter, is_error, NULL, NULL);
+
+  self->deduplicator = g_hash_table_new_full ((GHashFunc)ide_diagnostic_hash,
+                                              (GEqualFunc)ide_diagnostic_equal,
+                                              g_object_unref,
+                                              NULL);
+  self->pipeline_signals = ide_signal_group_new (IDE_TYPE_PIPELINE);
+  g_signal_connect_object (self->pipeline_signals,
+                           "bind",
+                           G_CALLBACK (gbp_buildui_status_popover_bind_pipeline),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (self->pipeline_signals,
+                           "unbind",
+                           G_CALLBACK (gbp_buildui_status_popover_unbind_pipeline),
+                           self,
+                           G_CONNECT_SWAPPED);
+  ide_signal_group_connect_object (self->pipeline_signals,
+                                   "diagnostic",
+                                   G_CALLBACK (gbp_buildui_status_popover_add_diagnsotic),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+
+  g_object_bind_property_full (self->warnings_model, "n-items",
+                               self->warnings, "title",
+                               G_BINDING_SYNC_CREATE,
+                               warnings_title_cb, NULL, NULL, NULL);
+  g_object_bind_property_full (self->errors_model, "n-items",
+                               self->errors, "title",
+                               G_BINDING_SYNC_CREATE,
+                               errors_title_cb, NULL, NULL, NULL);
+}
+
+static void
+gbp_buildui_status_popover_connect (GbpBuilduiStatusPopover *self,
+                                    IdeContext              *context)
+{
+  IdeBuildManager *build_manager;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  build_manager = ide_build_manager_from_context (context);
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  g_object_bind_property (build_manager, "pipeline",
+                          self->pipeline_signals, "target",
+                          G_BINDING_SYNC_CREATE);
+
+  IDE_EXIT;
+}
+
+GbpBuilduiStatusPopover *
+gbp_buildui_status_popover_new (IdeContext *context)
+{
+  GbpBuilduiStatusPopover *self;
+
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  self = g_object_new (GBP_TYPE_BUILDUI_STATUS_POPOVER, NULL);
+  gbp_buildui_status_popover_connect (self, context);
+
+  return self;
+}
+
+void
+gbp_buildui_status_popover_set_page (GbpBuilduiStatusPopover *self,
+                                     const char              *page)
+{
+  GtkWidget *visible_child;
+
+  g_return_if_fail (GBP_IS_BUILDUI_STATUS_POPOVER (self));
+  g_return_if_fail (page != NULL);
+
+  gtk_stack_set_visible_child_name (self->stack, page);
+
+  if ((visible_child = gtk_stack_get_visible_child (self->stack)))
+    gtk_widget_child_focus (visible_child, GTK_DIR_TAB_FORWARD);
+}
diff --git a/src/plugins/buildui/gbp-buildui-status-popover.h 
b/src/plugins/buildui/gbp-buildui-status-popover.h
new file mode 100644
index 000000000..0027f670f
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-popover.h
@@ -0,0 +1,37 @@
+/* gbp-buildui-status-popover.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_STATUS_POPOVER (gbp_buildui_status_popover_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiStatusPopover, gbp_buildui_status_popover, GBP, BUILDUI_STATUS_POPOVER, 
GtkPopover)
+
+GbpBuilduiStatusPopover *gbp_buildui_status_popover_new      (IdeContext              *context);
+void                     gbp_buildui_status_popover_set_page (GbpBuilduiStatusPopover *self,
+                                                              const char              *page);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-status-popover.ui 
b/src/plugins/buildui/gbp-buildui-status-popover.ui
new file mode 100644
index 000000000..6ceddbe0b
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-status-popover.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpBuilduiStatusPopover" parent="GtkPopover">
+    <property name="width-request">400</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkStackSwitcher">
+            <property name="stack">stack</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkFrame">
+            <child>
+              <object class="GtkStack" id="stack">
+                <property name="hhomogeneous">false</property>
+                <property name="vhomogeneous">false</property>
+                <property name="transition-duration">200</property>
+                <property name="transition-type">crossfade</property>
+                <child>
+                  <object class="GtkStackPage" id="errors">
+                    <property name="use-underline">true</property>
+                    <property name="name">errors</property>
+                    <property name="child">
+                      <object class="GtkScrolledWindow">
+                        <property name="has-frame">true</property>
+                        <property name="propagate-natural-height">true</property>
+                        <property name="propagate-natural-width">true</property>
+                        <property name="min-content-height">300</property>
+                        <property name="max-content-height">600</property>
+                        <property name="min-content-width">400</property>
+                        <property name="max-content-width">400</property>
+                        <child>
+                          <object class="GtkListView">
+                            <signal name="activate" handler="gbp_buildui_status_popover_activate_cb" 
swapped="true" object="GbpBuilduiStatusPopover"/>
+                            <property name="orientation">vertical</property>
+                            <property name="single-click-activate">True</property>
+                            <property name="factory">
+                              <object class="GtkBuilderListItemFactory">
+                                <property 
name="resource">/plugins/buildui/gbp-buildui-status-popover-row.ui</property>
+                              </object>
+                            </property>
+                            <property name="model">
+                              <object class="GtkNoSelection">
+                                <property name="model">
+                                  <object class="GtkFilterListModel" id="errors_model">
+                                    <property name="model">diagnostics</property>
+                                    <property name="filter">error_filter</property>
+                                  </object>
+                                </property>
+                              </object>
+                            </property>
+                          </object>
+                        </child>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkStackPage" id="warnings">
+                    <property name="use-underline">true</property>
+                    <property name="name">warnings</property>
+                    <property name="child">
+                      <object class="GtkScrolledWindow">
+                        <property name="has-frame">true</property>
+                        <property name="propagate-natural-height">true</property>
+                        <property name="propagate-natural-width">true</property>
+                        <property name="min-content-height">300</property>
+                        <property name="max-content-height">600</property>
+                        <property name="min-content-width">400</property>
+                        <property name="max-content-width">400</property>
+                        <child>
+                          <object class="GtkListView">
+                            <signal name="activate" handler="gbp_buildui_status_popover_activate_cb" 
swapped="true" object="GbpBuilduiStatusPopover"/>
+                            <property name="orientation">vertical</property>
+                            <property name="single-click-activate">True</property>
+                            <property name="factory">
+                              <object class="GtkBuilderListItemFactory">
+                                <property 
name="resource">/plugins/buildui/gbp-buildui-status-popover-row.ui</property>
+                              </object>
+                            </property>
+                            <property name="model">
+                              <object class="GtkNoSelection">
+                                <property name="model">
+                                  <object class="GtkFilterListModel" id="warnings_model">
+                                    <property name="model">diagnostics</property>
+                                    <property name="filter">warning_filter</property>
+                                  </object>
+                                </property>
+                              </object>
+                            </property>
+                          </object>
+                        </child>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GListStore" id="diagnostics">
+    <property name="item-type">IdeDiagnostic</property>
+  </object>
+  <object class="GtkCustomFilter" id="warning_filter"/>
+  <object class="GtkCustomFilter" id="error_filter"/>
+</interface>
diff --git a/src/plugins/buildui/gbp-buildui-targets-dialog.c 
b/src/plugins/buildui/gbp-buildui-targets-dialog.c
new file mode 100644
index 000000000..24a33836e
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-targets-dialog.c
@@ -0,0 +1,251 @@
+/*
+ * gbp-buildui-targets-dialog.c
+ *
+ * Copyright 2022 Christian Hergert <>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-buildui-targets-dialog"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+
+#include <libide-gui.h>
+
+#include "gbp-buildui-targets-dialog.h"
+
+struct _GbpBuilduiTargetsDialog
+{
+  AdwWindow   parent_instance;
+  GtkListBox *list_box;
+  GtkSpinner *spinner;
+  guint       busy : 1;
+};
+
+G_DEFINE_FINAL_TYPE (GbpBuilduiTargetsDialog, gbp_buildui_targets_dialog, ADW_TYPE_WINDOW)
+
+enum {
+  PROP_0,
+  PROP_BUSY,
+  PROP_CONTEXT,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static GtkWidget *
+create_target_row (gpointer item,
+                   gpointer user_data)
+{
+  IdeBuildTarget *target = item;
+  g_autoptr(GVariant) namev = NULL;
+  IdeArtifactKind kind;
+  AdwActionRow *row;
+  const char *name;
+  GtkWidget *check;
+  const char *pill_label;
+
+  g_assert (IDE_IS_BUILD_TARGET (target));
+
+  name = ide_build_target_get_name (target);
+  namev = g_variant_take_ref (g_variant_new_string (name ? name : ""));
+
+  check = g_object_new (GTK_TYPE_CHECK_BUTTON,
+                        "action-name", "build-manager.default-build-target",
+                        "css-classes", IDE_STRV_INIT ("checkimage"),
+                        "action-target", namev,
+                        "valign", GTK_ALIGN_CENTER,
+                        "can-focus", FALSE,
+                        NULL);
+  row = g_object_new (ADW_TYPE_ACTION_ROW,
+                      "title", ide_build_target_get_display_name (item),
+                      "activatable-widget", check,
+                      NULL);
+
+  kind = ide_build_target_get_kind (target);
+
+  switch (kind)
+    {
+    case IDE_ARTIFACT_KIND_SHARED_LIBRARY:
+      pill_label = _("Shared");
+      break;
+
+    case IDE_ARTIFACT_KIND_STATIC_LIBRARY:
+      pill_label = _("Static");
+      break;
+
+    case IDE_ARTIFACT_KIND_EXECUTABLE:
+      pill_label = _("Executable");
+      break;
+
+    case IDE_ARTIFACT_KIND_FILE:
+    case IDE_ARTIFACT_KIND_NONE:
+    default:
+      pill_label = NULL;
+      break;
+    }
+
+  if (pill_label != NULL)
+    adw_action_row_add_suffix (row,
+                               g_object_new (GTK_TYPE_LABEL,
+                                             "label", pill_label,
+                                             "css-name", "button",
+                                             "css-classes", IDE_STRV_INIT ("pill", "small"),
+                                             "valign", GTK_ALIGN_CENTER,
+                                             NULL));
+  adw_action_row_add_suffix (row, check);
+
+  return GTK_WIDGET (row);
+}
+
+static void
+gbp_buildui_targets_dialog_list_targets_cb (GObject      *object,
+                                            GAsyncResult *result,
+                                            gpointer      user_data)
+{
+  IdeBuildManager *build_manager = (IdeBuildManager *)object;
+  g_autoptr(GbpBuilduiTargetsDialog) self = user_data;
+  g_autoptr(GListModel) model = NULL;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (GBP_IS_BUILDUI_TARGETS_DIALOG (self));
+
+  self->busy = FALSE;
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+
+  if (!(model = ide_build_manager_list_targets_finish (build_manager, result, &error)))
+    {
+      if (!ide_error_ignore (error))
+        ide_object_warning (build_manager,
+                            /* translators: %s is replaced with the error message */
+                            _("Failed to list build targets: %s"),
+                            error->message);
+      IDE_EXIT;
+    }
+
+  gtk_list_box_bind_model (self->list_box, model, create_target_row, NULL, NULL);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_targets_dialog_set_context (GbpBuilduiTargetsDialog *self,
+                                        IdeContext              *context)
+{
+  IdeBuildManager *build_manager;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_BUILDUI_TARGETS_DIALOG (self));
+  g_assert (!context || IDE_IS_CONTEXT (context));
+
+  if (context == NULL)
+    IDE_EXIT;
+
+  self->busy = TRUE;
+
+  build_manager = ide_build_manager_from_context (context);
+  gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                  "build-manager",
+                                  G_ACTION_GROUP (build_manager));
+  ide_build_manager_list_targets_async (build_manager,
+                                        NULL,
+                                        gbp_buildui_targets_dialog_list_targets_cb,
+                                        g_object_ref (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_buildui_targets_dialog_get_property (GObject    *object,
+                                         guint       prop_id,
+                                         GValue     *value,
+                                         GParamSpec *pspec)
+{
+  GbpBuilduiTargetsDialog *self = GBP_BUILDUI_TARGETS_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_BUSY:
+      g_value_set_boolean (value, self->busy);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_targets_dialog_set_property (GObject      *object,
+                                         guint         prop_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  GbpBuilduiTargetsDialog *self = GBP_BUILDUI_TARGETS_DIALOG (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONTEXT:
+      gbp_buildui_targets_dialog_set_context (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_buildui_targets_dialog_class_init (GbpBuilduiTargetsDialogClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = gbp_buildui_targets_dialog_get_property;
+  object_class->set_property = gbp_buildui_targets_dialog_set_property;
+
+  properties [PROP_BUSY] =
+    g_param_spec_boolean ("busy", NULL, NULL,
+                          FALSE,
+                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_CONTEXT] =
+    g_param_spec_object ("context", NULL, NULL,
+                         IDE_TYPE_CONTEXT,
+                         (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/plugins/buildui/gbp-buildui-targets-dialog.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiTargetsDialog, list_box);
+  gtk_widget_class_bind_template_child (widget_class, GbpBuilduiTargetsDialog, spinner);
+}
+
+static void
+gbp_buildui_targets_dialog_init (GbpBuilduiTargetsDialog *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/src/plugins/buildui/gbp-buildui-targets-dialog.h 
b/src/plugins/buildui/gbp-buildui-targets-dialog.h
new file mode 100644
index 000000000..0c3efaae3
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-targets-dialog.h
@@ -0,0 +1,35 @@
+/* gbp-buildui-targets-dialog.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <adwaita.h>
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_BUILDUI_TARGETS_DIALOG (gbp_buildui_targets_dialog_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpBuilduiTargetsDialog, gbp_buildui_targets_dialog, GBP, BUILDUI_TARGETS_DIALOG, 
AdwWindow)
+
+GtkWidget *gbp_buildui_targets_dialog_new (IdeContext *context);
+
+G_END_DECLS
diff --git a/src/plugins/buildui/gbp-buildui-targets-dialog.ui 
b/src/plugins/buildui/gbp-buildui-targets-dialog.ui
new file mode 100644
index 000000000..206053c2d
--- /dev/null
+++ b/src/plugins/buildui/gbp-buildui-targets-dialog.ui
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpBuilduiTargetsDialog" parent="AdwWindow">
+    <property name="title" translatable="yes">Select Build Target</property>
+    <property name="default-width">700</property>
+    <property name="default-height">550</property>
+    <child type="content">
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="AdwHeaderBar">
+          </object>
+        </child>
+        <child>
+          <object class="AdwPreferencesPage">
+            <child>
+              <object class="AdwPreferencesGroup">
+                <property name="title" translatable="yes">Available Build Targets</property>
+                <property name="description" translatable="yes">Some targets may not be available until the 
project has been configured.</property>
+                <property name="header-suffix">
+                  <object class="GtkSpinner" id="spinner">
+                    <property name="spinning" bind-source="GbpBuilduiTargetsDialog" bind-property="busy" 
bind-flags="sync-create"/>
+                  </object>
+                </property>
+                <child>
+                  <object class="AdwActionRow">
+                    <property name="title" translatable="yes">Build System Default</property>
+                    <property name="subtitle" translatable="yes">This selection allows the build system to 
choose the best default candidate</property>
+                    <property name="activatable-widget">default_target</property>
+                    <child type="suffix">
+                      <object class="GtkCheckButton" id="default_target">
+                        <property name="action-name">build-manager.default-build-target</property>
+                        <property name="action-target">''</property>
+                        <style>
+                          <class name="checkimage"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkListBox" id="list_box">
+                    <property name="margin-top">12</property>
+                    <property name="selection-mode">none</property>
+                    <style>
+                      <class name="boxed-list"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/buildui/gbp-buildui-tree-addin.c b/src/plugins/buildui/gbp-buildui-tree-addin.c
index 883e9fd6a..92edc4691 100644
--- a/src/plugins/buildui/gbp-buildui-tree-addin.c
+++ b/src/plugins/buildui/gbp-buildui-tree-addin.c
@@ -35,8 +35,14 @@
 struct _GbpBuilduiTreeAddin
 {
   GObject       parent_instance;
+
+  /* Borrowed references */
   IdeTree      *tree;
   IdeTreeModel *model;
+
+  /* Owned references */
+  GtkWidget    *pane;
+  GActionGroup *group;
 };
 
 typedef struct
@@ -257,59 +263,17 @@ gbp_buildui_tree_addin_action_rebuild (GSimpleAction *action,
   ide_build_manager_rebuild_async (build_manager, IDE_PIPELINE_PHASE_BUILD, targets, NULL, NULL, NULL);
 }
 
-static void
-gbp_buildui_tree_addin_action_run (GSimpleAction *action,
-                                   GVariant      *param,
-                                   gpointer       user_data)
-{
-  GbpBuilduiTreeAddin *self = user_data;
-  IdeBuildManager *build_manager;
-  IdeBuildTarget *target;
-  IdeRunManager *run_manager;
-  IdeTreeNode *node;
-  IdeContext *context;
-  const gchar *handler;
-
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (G_IS_SIMPLE_ACTION (action));
-  g_assert (param != NULL);
-  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
-  g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
-
-  if (!(context = ide_widget_get_context (GTK_WIDGET (self->tree))) ||
-      !(build_manager = ide_build_manager_from_context (context)) ||
-      !(node = ide_tree_get_selected_node (self->tree)) ||
-      !ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) ||
-      !(target = ide_tree_node_get_item (node)))
-    return;
-
-  run_manager = ide_run_manager_from_context (context);
-  handler = g_variant_get_string (param, NULL);
-
-  if (ide_str_empty0 (handler))
-    ide_run_manager_set_handler (run_manager, NULL);
-  else
-    ide_run_manager_set_handler (run_manager, handler);
-
-  ide_run_manager_run_async (run_manager,
-                             target,
-                             NULL,
-                             NULL,
-                             NULL);
-}
-
 static void
 gbp_buildui_tree_addin_load (IdeTreeAddin *addin,
                              IdeTree      *tree,
                              IdeTreeModel *model)
 {
   GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
-  g_autoptr(GSimpleActionGroup) group = NULL;
   IdeContext *context;
+  GtkWidget *pane;
   static const GActionEntry actions[] = {
     { "build", gbp_buildui_tree_addin_action_build },
     { "rebuild", gbp_buildui_tree_addin_action_rebuild },
-    { "run-with-handler", gbp_buildui_tree_addin_action_run, "s" },
   };
 
   g_assert (IDE_IS_MAIN_THREAD ());
@@ -325,12 +289,16 @@ gbp_buildui_tree_addin_load (IdeTreeAddin *addin,
   if (!ide_context_has_project (context))
     return;
 
-  group = g_simple_action_group_new ();
-  g_action_map_add_action_entries (G_ACTION_MAP (group),
+  pane = gtk_widget_get_ancestor (GTK_WIDGET (tree), IDE_TYPE_PANE);
+  g_assert (IDE_IS_PANE (pane));
+
+  self->pane = g_object_ref (pane);
+  self->group = G_ACTION_GROUP (g_simple_action_group_new ());
+  g_action_map_add_action_entries (G_ACTION_MAP (self->group),
                                    actions,
                                    G_N_ELEMENTS (actions),
                                    self);
-  gtk_widget_insert_action_group (GTK_WIDGET (tree), "buildui", G_ACTION_GROUP (group));
+  gtk_widget_insert_action_group (pane, "buildui", self->group);
 }
 
 static void
@@ -345,8 +313,10 @@ gbp_buildui_tree_addin_unload (IdeTreeAddin *addin,
   g_assert (IDE_IS_TREE (tree));
   g_assert (IDE_IS_TREE_MODEL (model));
 
-  gtk_widget_insert_action_group (GTK_WIDGET (tree), "buildui", NULL);
+  gtk_widget_insert_action_group (self->pane, "buildui", NULL);
 
+  g_clear_object (&self->pane);
+  g_clear_object (&self->group);
   self->model = NULL;
   self->tree = NULL;
 }
@@ -356,8 +326,8 @@ gbp_buildui_tree_addin_selection_changed (IdeTreeAddin *addin,
                                           IdeTreeNode  *node)
 {
   GbpBuilduiTreeAddin *self = (GbpBuilduiTreeAddin *)addin;
-  IdeBuildTarget *target;
   IdeContext *context;
+  GAction *action;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_BUILDUI_TREE_ADDIN (self));
@@ -368,19 +338,13 @@ gbp_buildui_tree_addin_selection_changed (IdeTreeAddin *addin,
   if (!ide_context_has_project (context))
     return;
 
-  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "build",
-                             "enabled", node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET),
-                             NULL);
-  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "rebuild",
-                             "enabled", node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET),
-                             NULL);
-  dzl_gtk_widget_action_set (GTK_WIDGET (self->tree), "buildui", "run-with-handler",
-                             "enabled", node &&
-                                        ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET) &&
-                                        (target = ide_tree_node_get_item (node)) &&
-                                        ide_build_target_get_install (target) &&
-                                        ide_build_target_get_kind (target) == IDE_ARTIFACT_KIND_EXECUTABLE,
-                             NULL);
+  action = g_action_map_lookup_action (G_ACTION_MAP (self->group), "build");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                               node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET));
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (self->group), "rebuild");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+                               node && ide_tree_node_holds (node, IDE_TYPE_BUILD_TARGET));
 }
 
 static void
diff --git a/src/plugins/buildui/gbp-buildui-workspace-addin.c 
b/src/plugins/buildui/gbp-buildui-workspace-addin.c
index 0ea51bec7..bf9c8d7fe 100644
--- a/src/plugins/buildui/gbp-buildui-workspace-addin.c
+++ b/src/plugins/buildui/gbp-buildui-workspace-addin.c
@@ -22,38 +22,38 @@
 
 #include "config.h"
 
-#include <dazzle.h>
 #include <glib/gi18n.h>
 #include <libide-editor.h>
 #include <libide-foundry.h>
 #include <libide-gui.h>
 
-#include "gbp-buildui-config-surface.h"
 #include "gbp-buildui-log-pane.h"
 #include "gbp-buildui-omni-bar-section.h"
 #include "gbp-buildui-pane.h"
+#include "gbp-buildui-runnables-dialog.h"
+#include "gbp-buildui-status-indicator.h"
+#include "gbp-buildui-status-popover.h"
+#include "gbp-buildui-targets-dialog.h"
 #include "gbp-buildui-workspace-addin.h"
 
 struct _GbpBuilduiWorkspaceAddin
 {
-  GObject                   parent_instance;
+  GObject                    parent_instance;
 
   /* Borrowed references */
-  IdeWorkspace             *workspace;
-  GbpBuilduiConfigSurface  *surface;
-  GbpBuilduiOmniBarSection *omni_bar_section;
-  GbpBuilduiLogPane        *log_pane;
-  GbpBuilduiPane           *pane;
-  GtkBox                   *diag_box;
-  GtkImage                 *error_image;
-  GtkLabel                 *error_label;
-  GtkImage                 *warning_image;
-  GtkLabel                 *warning_label;
-  GtkButton                *build_button;
-  GtkButton                *cancel_button;
+  IdeWorkspace              *workspace;
+  GbpBuilduiOmniBarSection  *omni_bar_section;
+  GbpBuilduiLogPane         *log_pane;
+  GbpBuilduiPane            *pane;
+  GtkBox                    *diag_box;
+  GtkImage                  *error_image;
+  GtkLabel                  *error_label;
+  GtkImage                  *warning_image;
+  GtkLabel                  *warning_label;
+  GtkMenuButton             *status_button;
 
   /* Owned references */
-  DzlSignalGroup           *build_manager_signals;
+  IdeSignalGroup           *build_manager_signals;
 };
 
 static void
@@ -82,7 +82,7 @@ gbp_buildui_workspace_addin_notify_error_count (GbpBuilduiWorkspaceAddin *self,
   gtk_widget_set_visible (GTK_WIDGET (self->error_image), TRUE);
 
   if (count > 0)
-    dzl_dock_item_needs_attention (DZL_DOCK_ITEM (self->pane));
+    panel_widget_set_needs_attention (PANEL_WIDGET (self->pane), TRUE);
 }
 
 static void
@@ -111,7 +111,7 @@ gbp_buildui_workspace_addin_notify_warning_count (GbpBuilduiWorkspaceAddin *self
   gtk_widget_set_visible (GTK_WIDGET (self->warning_image), TRUE);
 
   if (count > 0)
-    dzl_dock_item_needs_attention (DZL_DOCK_ITEM (self->pane));
+    panel_widget_set_needs_attention (PANEL_WIDGET (self->pane), TRUE);
 }
 
 static void
@@ -135,27 +135,32 @@ gbp_buildui_workspace_addin_notify_busy (GbpBuilduiWorkspaceAddin *self,
                                          GParamSpec               *pspec,
                                          IdeBuildManager          *build_manager)
 {
+  IdeOmniBar *omni_bar;
   gboolean busy;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+  g_assert (IDE_IS_PRIMARY_WORKSPACE (self->workspace));
 
+  omni_bar = ide_primary_workspace_get_omni_bar (IDE_PRIMARY_WORKSPACE (self->workspace));
   busy = ide_build_manager_get_busy (build_manager);
 
-  gtk_widget_set_visible (GTK_WIDGET (self->build_button), !busy);
-  gtk_widget_set_visible (GTK_WIDGET (self->cancel_button), busy);
+  g_object_set (omni_bar,
+                "icon-name", busy ? "builder-build-stop-symbolic" : "builder-build-symbolic",
+                "action-name", busy ? "build-manager.cancel" : "build-manager.build",
+                NULL);
 }
 
 static void
 gbp_buildui_workspace_addin_bind_build_manager (GbpBuilduiWorkspaceAddin *self,
                                                 IdeBuildManager          *build_manager,
-                                                DzlSignalGroup           *signals)
+                                                IdeSignalGroup           *signals)
 {
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
-  g_assert (DZL_IS_SIGNAL_GROUP (signals));
+  g_assert (IDE_IS_SIGNAL_GROUP (signals));
 
   gbp_buildui_workspace_addin_notify_busy (self, NULL, build_manager);
   gbp_buildui_workspace_addin_notify_pipeline (self, NULL, build_manager);
@@ -174,38 +179,79 @@ on_view_output_cb (GSimpleAction *action,
   g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
 
-  ide_widget_reveal_and_grab (GTK_WIDGET (self->log_pane));
+  panel_widget_raise (PANEL_WIDGET (self->log_pane));
+  gtk_widget_grab_focus (GTK_WIDGET (self->log_pane));
 }
 
 static void
-on_edit_config_cb (GSimpleAction *action,
-                   GVariant      *param,
-                   gpointer       user_data)
+select_build_target_action (GSimpleAction *action,
+                            GVariant      *param,
+                            gpointer       user_data)
 {
   GbpBuilduiWorkspaceAddin *self = user_data;
-  IdeConfigManager *config_manager;
-  IdeConfig *config;
+  GbpBuilduiTargetsDialog *dialog;
   IdeContext *context;
-  const gchar *id;
 
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
-  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+  g_assert (G_IS_SIMPLE_ACTION (action));
+
+  context = ide_workspace_get_context (self->workspace);
+  dialog = g_object_new (GBP_TYPE_BUILDUI_TARGETS_DIALOG,
+                         "context", context,
+                         "transient-for", self->workspace,
+                         "modal", TRUE,
+                         NULL);
+
+  gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+select_run_command_action (GSimpleAction *action,
+                           GVariant      *param,
+                           gpointer       user_data)
+{
+  GbpBuilduiWorkspaceAddin *self = user_data;
+  GbpBuilduiRunnablesDialog *dialog;
+  IdeContext *context;
 
-  ide_workspace_set_visible_surface_name (self->workspace, "buildui");
+  g_assert (G_IS_SIMPLE_ACTION (action));
 
-  context = ide_widget_get_context (GTK_WIDGET (self->workspace));
-  config_manager = ide_config_manager_from_context (context);
-  id = g_variant_get_string (param, NULL);
-  config = ide_config_manager_get_config (config_manager, id);
+  context = ide_workspace_get_context (self->workspace);
+  dialog = g_object_new (GBP_TYPE_BUILDUI_RUNNABLES_DIALOG,
+                         "context", context,
+                         "transient-for", self->workspace,
+                         "modal", TRUE,
+                         NULL);
 
-  if (config != NULL)
-    gbp_buildui_config_surface_set_config (self->surface, config);
+  gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+show_status_popover (GSimpleAction *action,
+                     GVariant      *param,
+                     gpointer       user_data)
+{
+  GbpBuilduiWorkspaceAddin *self = user_data;
+  GtkPopover *popover;
+
+  IDE_ENTRY;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+  g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
+
+  popover = gtk_menu_button_get_popover (self->status_button);
+  gbp_buildui_status_popover_set_page (GBP_BUILDUI_STATUS_POPOVER (popover),
+                                       g_variant_get_string (param, NULL));
+  gtk_menu_button_popup (self->status_button);
+
+  IDE_EXIT;
 }
 
 static const GActionEntry actions[] = {
-  { "edit-config", on_edit_config_cb, "s" },
-  { "view-output", on_view_output_cb },
+  { "show-build-log", on_view_output_cb },
+  { "select-build-target", select_build_target_action },
+  { "select-run-command", select_run_command_action },
+  { "show-build-status-popover", show_status_popover, "s" },
 };
 
 static void
@@ -232,7 +278,7 @@ gbp_buildui_workspace_addin_build_started (GbpBuilduiWorkspaceAddin *self,
       gbp_buildui_log_pane_clear (self->log_pane);
 
   if (phase > IDE_PIPELINE_PHASE_CONFIGURE)
-    dzl_dock_item_present (DZL_DOCK_ITEM (self->log_pane));
+    panel_widget_raise (PANEL_WIDGET (self->log_pane));
 
   IDE_EXIT;
 }
@@ -242,17 +288,14 @@ gbp_buildui_workspace_addin_load (IdeWorkspaceAddin *addin,
                                   IdeWorkspace      *workspace)
 {
   GbpBuilduiWorkspaceAddin *self = (GbpBuilduiWorkspaceAddin *)addin;
-  IdeConfigManager *config_manager;
+  g_autoptr(IdePanelPosition) pane_position = NULL;
+  g_autoptr(IdePanelPosition) log_position = NULL;
   PangoAttrList *small_attrs = NULL;
-  DzlShortcutController *shortcuts;
-  IdeEditorSidebar *sidebar;
   IdeBuildManager *build_manager;
+  PanelStatusbar *statusbar;
   IdeWorkbench *workbench;
-  IdeHeaderBar *headerbar;
-  IdeSurface *surface;
   IdeOmniBar *omnibar;
   IdeContext *context;
-  GtkWidget *utilities;
 
   g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace));
@@ -264,35 +307,29 @@ gbp_buildui_workspace_addin_load (IdeWorkspaceAddin *addin,
                                    G_N_ELEMENTS (actions),
                                    self);
 
-  shortcuts = dzl_shortcut_controller_find (GTK_WIDGET (workspace));
-  dzl_shortcut_controller_add_command_action (shortcuts,
-                                              "org.gnome.builder.buildui.build",
-                                              "<Control>F7",
-                                              DZL_SHORTCUT_PHASE_GLOBAL | DZL_SHORTCUT_PHASE_CAPTURE,
-                                              "build-manager.build");
-  dzl_shortcut_controller_add_command_action (shortcuts,
-                                              "org.gnome.builder.buildui.rebuild",
-                                              "<Control><Shift>F7",
-                                              DZL_SHORTCUT_PHASE_GLOBAL | DZL_SHORTCUT_PHASE_CAPTURE,
-                                              "build-manager.rebuild");
-
-  headerbar = ide_workspace_get_header_bar (workspace);
-  omnibar = IDE_OMNI_BAR (hdy_header_bar_get_custom_title (HDY_HEADER_BAR (headerbar)));
+  omnibar = ide_primary_workspace_get_omni_bar (IDE_PRIMARY_WORKSPACE (workspace));
   workbench = ide_widget_get_workbench (GTK_WIDGET (workspace));
   context = ide_workbench_get_context (workbench);
   build_manager = ide_build_manager_from_context (context);
-  config_manager = ide_config_manager_from_context (context);
+
+  statusbar = ide_workspace_get_statusbar (workspace);
+  self->status_button = g_object_new (GTK_TYPE_MENU_BUTTON,
+                                      "child", gbp_buildui_status_indicator_new (context),
+                                      "popover", gbp_buildui_status_popover_new (context),
+                                      "direction", GTK_ARROW_UP,
+                                      "focus-on-click", FALSE,
+                                      NULL);
+  panel_statusbar_add_prefix (statusbar, 1000, GTK_WIDGET (self->status_button));
 
   small_attrs = pango_attr_list_new ();
   pango_attr_list_insert (small_attrs, pango_attr_scale_new (0.833333));
 
   self->diag_box = g_object_new (GTK_TYPE_BOX,
                                  "orientation", GTK_ORIENTATION_HORIZONTAL,
-                                 "visible", TRUE,
                                  NULL);
   g_signal_connect (self->diag_box,
                     "destroy",
-                    G_CALLBACK (gtk_widget_destroyed),
+                    G_CALLBACK (ide_gtk_widget_destroyed),
                     &self->diag_box);
   ide_omni_bar_add_status_icon (omnibar, GTK_WIDGET (self->diag_box), 0);
 
@@ -302,16 +339,18 @@ gbp_buildui_workspace_addin_load (IdeWorkspaceAddin *addin,
                                     "margin-start", 4,
                                     "pixel-size", 12,
                                     "valign", GTK_ALIGN_BASELINE,
+                                    "visible", FALSE,
                                     NULL);
-  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->error_image));
+  gtk_box_append (self->diag_box, GTK_WIDGET (self->error_image));
 
   self->error_label = g_object_new (GTK_TYPE_LABEL,
                                     "attributes", small_attrs,
                                     "margin-end", 2,
                                     "margin-start", 2,
                                     "valign", GTK_ALIGN_BASELINE,
+                                    "visible", FALSE,
                                     NULL);
-  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->error_label));
+  gtk_box_append (self->diag_box, GTK_WIDGET (self->error_label));
 
   self->warning_image = g_object_new (GTK_TYPE_IMAGE,
                                       "icon-name", "dialog-warning-symbolic",
@@ -319,118 +358,75 @@ gbp_buildui_workspace_addin_load (IdeWorkspaceAddin *addin,
                                       "margin-start", 4,
                                       "pixel-size", 12,
                                       "valign", GTK_ALIGN_BASELINE,
+                                      "visible", FALSE,
                                       NULL);
-  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->warning_image));
+  gtk_box_append (self->diag_box, GTK_WIDGET (self->warning_image));
 
   self->warning_label = g_object_new (GTK_TYPE_LABEL,
                                       "attributes", small_attrs,
                                       "margin-end", 2,
                                       "margin-start", 2,
                                       "valign", GTK_ALIGN_BASELINE,
+                                      "visible", FALSE,
                                       NULL);
-  gtk_container_add (GTK_CONTAINER (self->diag_box), GTK_WIDGET (self->warning_label));
+  gtk_box_append (self->diag_box, GTK_WIDGET (self->warning_label));
 
   g_clear_pointer (&small_attrs, pango_attr_list_unref);
 
-  self->omni_bar_section = g_object_new (GBP_TYPE_BUILDUI_OMNI_BAR_SECTION,
-                                         "visible", TRUE,
-                                         NULL);
+  self->omni_bar_section = g_object_new (GBP_TYPE_BUILDUI_OMNI_BAR_SECTION, NULL);
   g_signal_connect (self->omni_bar_section,
                     "destroy",
-                    G_CALLBACK (gtk_widget_destroyed),
+                    G_CALLBACK (ide_gtk_widget_destroyed),
                     &self->omni_bar_section);
   ide_omni_bar_add_popover_section (omnibar, GTK_WIDGET (self->omni_bar_section), 0);
   gbp_buildui_omni_bar_section_set_context (self->omni_bar_section, context);
 
-  self->build_button = g_object_new (GTK_TYPE_BUTTON,
-                                     "action-name", "build-manager.build",
-                                     "child", g_object_new (GTK_TYPE_IMAGE,
-                                                            "icon-name", "builder-build-symbolic",
-                                                            "visible", TRUE,
-                                                            NULL),
-                                     "focus-on-click", FALSE,
-                                     "has-tooltip", TRUE,
-                                     "visible", TRUE,
-                                     NULL);
-  ide_omni_bar_add_button (omnibar, GTK_WIDGET (self->build_button), GTK_PACK_END, 0);
-
-  self->cancel_button = g_object_new (GTK_TYPE_BUTTON,
-                                      "action-name", "build-manager.cancel",
-                                      "child", g_object_new (GTK_TYPE_IMAGE,
-                                                             "icon-name", "builder-build-stop-symbolic",
-                                                             "visible", TRUE,
-                                                             NULL),
-                                      "focus-on-click", FALSE,
-                                      "has-tooltip", TRUE,
-                                      "visible", TRUE,
-                                      NULL);
-  ide_omni_bar_add_button (omnibar, GTK_WIDGET (self->cancel_button), GTK_PACK_END, 0);
+  log_position = ide_panel_position_new ();
+  ide_panel_position_set_edge (log_position, PANEL_DOCK_POSITION_BOTTOM);
+  ide_panel_position_set_depth (log_position, 2);
 
-  surface = ide_workspace_get_surface_by_name (workspace, "editor");
-  utilities = ide_editor_surface_get_utilities (IDE_EDITOR_SURFACE (surface));
-  sidebar = ide_editor_surface_get_sidebar (IDE_EDITOR_SURFACE (surface));
+  self->log_pane = g_object_new (GBP_TYPE_BUILDUI_LOG_PANE, NULL);
+  ide_workspace_add_pane (workspace, IDE_PANE (self->log_pane), log_position);
 
-  self->log_pane = g_object_new (GBP_TYPE_BUILDUI_LOG_PANE,
-                                 "visible", TRUE,
-                                 NULL);
-  gtk_container_add (GTK_CONTAINER (utilities), GTK_WIDGET (self->log_pane));
-
-  self->pane = g_object_new (GBP_TYPE_BUILDUI_PANE,
-                             "visible", TRUE,
-                             NULL);
-  ide_editor_sidebar_add_section (sidebar,
-                                  "build-issues",
-                                  _("Build Issues"),
-                                  "builder-build-issues-symbolic",
-                                  NULL, NULL,
-                                  GTK_WIDGET (self->pane),
-                                  100);
-
-  self->surface = g_object_new (GBP_TYPE_BUILDUI_CONFIG_SURFACE,
-                                "config-manager", config_manager,
-                                "icon-name", "builder-build-configure-symbolic",
-                                "title", _("Build Preferences"),
-                                "name", "buildui",
-                                "visible", TRUE,
-                                NULL);
-  g_signal_connect (self->surface,
-                    "destroy",
-                    G_CALLBACK (gtk_widget_destroyed),
-                    &self->surface);
-  ide_workspace_add_surface (workspace, IDE_SURFACE (self->surface));
+  pane_position = ide_panel_position_new ();
+  ide_panel_position_set_edge (pane_position, PANEL_DOCK_POSITION_START);
+  ide_panel_position_set_depth (pane_position, 1);
+
+  self->pane = g_object_new (GBP_TYPE_BUILDUI_PANE, NULL);
+  ide_workspace_add_pane (workspace, IDE_PANE (self->pane), pane_position);
 
-  self->build_manager_signals = dzl_signal_group_new (IDE_TYPE_BUILD_MANAGER);
+  self->build_manager_signals = ide_signal_group_new (IDE_TYPE_BUILD_MANAGER);
   g_signal_connect_object (self->build_manager_signals,
                            "bind",
                            G_CALLBACK (gbp_buildui_workspace_addin_bind_build_manager),
                            self,
                            G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::error-count",
                                    G_CALLBACK (gbp_buildui_workspace_addin_notify_error_count),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::warning-count",
                                    G_CALLBACK (gbp_buildui_workspace_addin_notify_warning_count),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::pipeline",
                                    G_CALLBACK (gbp_buildui_workspace_addin_notify_pipeline),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "notify::busy",
                                    G_CALLBACK (gbp_buildui_workspace_addin_notify_busy),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_connect_object (self->build_manager_signals,
+  ide_signal_group_connect_object (self->build_manager_signals,
                                    "build-started",
                                    G_CALLBACK (gbp_buildui_workspace_addin_build_started),
                                    self,
                                    G_CONNECT_SWAPPED);
-  dzl_signal_group_set_target (self->build_manager_signals, build_manager);
+  ide_signal_group_set_target (self->build_manager_signals, build_manager);
 }
 
 static void
@@ -438,23 +434,25 @@ gbp_buildui_workspace_addin_unload (IdeWorkspaceAddin *addin,
                                     IdeWorkspace      *workspace)
 {
   GbpBuilduiWorkspaceAddin *self = (GbpBuilduiWorkspaceAddin *)addin;
+  PanelStatusbar *statusbar;
 
   g_assert (GBP_IS_BUILDUI_WORKSPACE_ADDIN (self));
   g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace));
 
+  statusbar = ide_workspace_get_statusbar (workspace);
+  panel_statusbar_remove (statusbar, GTK_WIDGET (self->status_button));
+  self->status_button = NULL;
+
   for (guint i = 0; i < G_N_ELEMENTS (actions); i++)
     g_action_map_remove_action (G_ACTION_MAP (workspace), actions[i].name);
 
   if (self->omni_bar_section)
-    gtk_widget_destroy (GTK_WIDGET (self->omni_bar_section));
+    gtk_widget_unparent (GTK_WIDGET (self->omni_bar_section));
 
   if (self->diag_box)
-    gtk_widget_destroy (GTK_WIDGET (self->diag_box));
-
-  if (self->surface)
-    gtk_widget_destroy (GTK_WIDGET (self->surface));
+    gtk_widget_unparent (GTK_WIDGET (self->diag_box));
 
-  dzl_signal_group_set_target (self->build_manager_signals, NULL);
+  ide_signal_group_set_target (self->build_manager_signals, NULL);
   g_clear_object (&self->build_manager_signals);
 
   self->workspace = NULL;
diff --git a/src/plugins/buildui/gtk/keybindings.json b/src/plugins/buildui/gtk/keybindings.json
new file mode 100644
index 000000000..b3232e0d2
--- /dev/null
+++ b/src/plugins/buildui/gtk/keybindings.json
@@ -0,0 +1,11 @@
+/* Build Actions */
+{ "trigger" : "<Control><Shift>l", "action" : "win.show-build-log", "when" : "hasProject()", "phase" : 
"capture" },
+{ "trigger" : "<Control><Alt><Shift>b", "action" : "build-manager.build", "when" : "hasProject()", "phase" : 
"capture" },
+
+/* Run Actions */
+{ "trigger" : "<Control><Shift>space", "action" : "run-manager.run", "when" : "hasProject()", "phase" : 
"capture" },
+
+/* Errors and Warnings Popover */
+{ "trigger" : "<Control><Shift>e", "action" : "win.show-build-status-popover", "args" : "'errors'", "when" : 
"hasErrors() || hasWarnings()", "phase" : "capture" },
+{ "trigger" : "<Control><Shift>w", "action" : "win.show-build-status-popover", "args" : "'warnings'", "when" 
: "hasErrors() || hasWarnings()", "phase" : "capture" },
+
diff --git a/src/plugins/buildui/gtk/menus.ui b/src/plugins/buildui/gtk/menus.ui
index 799ad1b20..df725cf7b 100644
--- a/src/plugins/buildui/gtk/menus.ui
+++ b/src/plugins/buildui/gtk/menus.ui
@@ -1,20 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <menu id="ide-primary-workspace-surfaces-menu">
-    <section id="ide-primary-workspace-surfaces-menu-section">
-      <item>
-        <attribute name="accel">&lt;alt&gt;comma</attribute>
-        <attribute name="id">surface-menu-config</attribute>
-        <attribute name="label" translatable="yes">Build Preferences</attribute>
-        <attribute name="role">normal</attribute>
-        <attribute name="action">win.surface</attribute>
-        <attribute name="target">buildui</attribute>
-        <attribute name="verb-icon-name">builder-build-configure-symbolic</attribute>
-      </item>
-    </section>
-  </menu>
   <menu id="project-tree-menu">
-    <section id="project-tree-menu-buildui">
+    <section id="project-tree-menu-foundry-section">
       <item>
         <attribute name="id">project-tree-menu-build</attribute>
         <attribute name="hidden-when">action-disabled</attribute>
@@ -41,4 +28,150 @@
       </submenu>
     </section>
   </menu>
+  <menu id="build-menu">
+    <item>
+      <attribute name="label" translatable="yes">Configure Project…</attribute>
+      <attribute name="action">workbench.configure</attribute>
+      <attribute name="accel">&lt;alt&gt;comma</attribute>
+    </item>
+    <section id="build-menu-target">
+      <item>
+        <attribute name="label" translatable="yes">Select Build Target…</attribute>
+        <attribute name="action">win.select-build-target</attribute>
+      </item>
+    </section>
+    <section id="build-commands">
+      <item>
+        <attribute name="label" translatable="yes">_Build</attribute>
+        <attribute name="action">build-manager.build</attribute>
+        <attribute name="accel">&lt;ctrl&gt;&lt;alt&gt;&lt;shift&gt;b</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Rebuild</attribute>
+        <attribute name="action">build-manager.rebuild</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Clean</attribute>
+        <attribute name="action">build-manager.clean</attribute>
+      </item>
+    </section>
+    <section id="build-export">
+      <item>
+        <attribute name="label" translatable="yes">_Install</attribute>
+        <attribute name="action">build-manager.install</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Deploy to Device…</attribute>
+        <attribute name="action">device-manager.deploy</attribute>
+      </item>
+      <item>
+        <!-- TODO: Instead of having a generic Export via the build-manager,
+          this should move into the Flatpak plugin and have it use
+          flatpak-builder directly (reusing our cachepoints) so that
+          the output is the same as using flatpak-builder from Flathub, etc.
+        -->
+        <attribute name="label" translatable="yes">_Export</attribute>
+        <attribute name="action">build-manager.export</attribute>
+      </item>
+    </section>
+    <section id="build-cork">
+      <item>
+        <attribute name="label" translatable="yes">Stop Build</attribute>
+        <attribute name="action">build-manager.cancel</attribute>
+      </item>
+    </section>
+    <section id="build-output">
+      <item>
+        <attribute name="label" translatable="yes">Show Build _Log</attribute>
+        <attribute name="action">win.show-build-log</attribute>
+        <attribute name="accel">&lt;ctrl&gt;&lt;shift&gt;l</attribute>
+      </item>
+    </section>
+    <section id="build-deps">
+      <item>
+        <attribute name="label" translatable="yes">Update Dependencies…</attribute>
+        <attribute name="action">win.update-dependencies</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Manage SDKs…</attribute>
+        <attribute name="action">app.preferences-page</attribute>
+        <attribute name="target" type="s">'sdks'</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="run-menu">
+    <section id="run-command-section">
+      <item>
+        <attribute name="label" translatable="yes">Select Run Command…</attribute>
+        <attribute name="action">win.select-run-command</attribute>
+      </item>
+    </section>
+    <section id="run-menu-observation-section">
+      <item>
+        <attribute name="id">default-run-handler</attribute>
+        <attribute name="action">run-manager.run-with-handler</attribute>
+        <attribute name="target" type="s">'run'</attribute>
+        <attribute name="label" translatable="yes">Run</attribute>
+        <attribute name="accel">&lt;Control&gt;&lt;Shift&gt;space</attribute>
+        <attribute name="verb-icon">builder-run-start-symbolic</attribute>
+      </item>
+    </section>
+    <section id="run-menu-tests-section"/>
+    <section id="run-menu-settings-section">
+      <attribute name="label" translatable="yes">Settings</attribute>
+      <submenu id="run-menu-appearance">
+        <attribute name="label" translatable="yes">Appearance</attribute>
+        <item>
+          <attribute name="label">Follow System Style</attribute>
+          <attribute name="role">radio</attribute>
+          <attribute name="action">run-manager.color-scheme</attribute>
+          <attribute name="target" type="s">'follow'</attribute>
+        </item>
+        <item>
+          <attribute name="label">Force Light</attribute>
+          <attribute name="role">radio</attribute>
+          <attribute name="action">run-manager.color-scheme</attribute>
+          <attribute name="target" type="s">'force-light'</attribute>
+        </item>
+        <item>
+          <attribute name="label">Force Dark</attribute>
+          <attribute name="role">radio</attribute>
+          <attribute name="action">run-manager.color-scheme</attribute>
+          <attribute name="target" type="s">'force-dark'</attribute>
+        </item>
+      </submenu>
+      <submenu id="run-menu-a11y">
+        <attribute name="label" translatable="yes">Accessibility</attribute>
+        <item>
+          <attribute name="label" translatable="yes">High Contrast</attribute>
+          <attribute name="role">check</attribute>
+          <attribute name="action">run-manager.high-contrast</attribute>
+        </item>
+        <section id="run-menu-a11y-text-direction">
+          <attribute name="label" translatable="yes">Text Direction</attribute>
+          <item>
+            <attribute name="label" translatable="yes">Left-to-Right</attribute>
+            <attribute name="role">check</attribute>
+            <attribute name="action">run-manager.text-direction</attribute>
+            <attribute name="target" type="s">'ltr'</attribute>
+          </item>
+          <item>
+            <attribute name="label" translatable="yes">Right-to-Left</attribute>
+            <attribute name="role">check</attribute>
+            <attribute name="action">run-manager.text-direction</attribute>
+            <attribute name="target" type="s">'rtl'</attribute>
+          </item>
+        </section>
+      </submenu>
+      <item>
+        <attribute name="id">run-menu-verbose-logging</attribute>
+        <attribute name="label" translatable="yes">Verbose Logging</attribute>
+        <attribute name="action">run-manager.messages-debug-all</attribute>
+        <attribute name="role">check</attribute>
+      </item>
+    </section>
+    <section id="run-menu-tools-section">
+      <attribute name="label" translatable="yes">Tools</attribute>
+    </section>
+  </menu>
 </interface>
diff --git a/src/plugins/buildui/meson.build b/src/plugins/buildui/meson.build
index 6524ce012..0020afbaf 100644
--- a/src/plugins/buildui/meson.build
+++ b/src/plugins/buildui/meson.build
@@ -1,14 +1,18 @@
 plugins_sources += files([
   'buildui-plugin.c',
-  'gbp-buildui-config-surface.c',
-  'gbp-buildui-config-view-addin.c',
+  #'gbp-buildui-config-view-addin.c',
   'gbp-buildui-editor-page-addin.c',
   'gbp-buildui-log-pane.c',
   'gbp-buildui-omni-bar-section.c',
   'gbp-buildui-pane.c',
+  'gbp-buildui-preferences-addin.c',
+  'gbp-buildui-runnables-dialog.c',
   'gbp-buildui-runtime-categories.c',
   'gbp-buildui-runtime-row.c',
   'gbp-buildui-stage-row.c',
+  'gbp-buildui-status-indicator.c',
+  'gbp-buildui-status-popover.c',
+  'gbp-buildui-targets-dialog.c',
   'gbp-buildui-tree-addin.c',
   'gbp-buildui-workspace-addin.c',
 ])


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]