diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 88c46076df612c996114946927f4aeed6bf42d2e..0f4c498c266a77d27729571a3d50db250c289d50 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -100,6 +100,10 @@ module Ci
       end
     end
 
+    def detailed_status
+      Gitlab::Ci::Status::Build::Factory.new(self).fabricate!
+    end
+
     def manual?
       self.when == 'manual'
     end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index cf90475f4d4502cd173cdec37156a1cf1aff7643..fce16174e2214531c2b7d65d12e66dee59c72587 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -131,4 +131,8 @@ class CommitStatus < ActiveRecord::Base
   def has_trace?
     false
   end
+
+  def detailed_status
+    Gitlab::Ci::Status::Factory.new(self).fabricate!
+  end
 end
diff --git a/lib/gitlab/ci/status/build/common.rb b/lib/gitlab/ci/status/build/common.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d3d7e03ee3f40dca407f5a9548016a64acc9f6de
--- /dev/null
+++ b/lib/gitlab/ci/status/build/common.rb
@@ -0,0 +1,54 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        module Common
+          def has_details?
+            true
+          end
+
+          def details_path
+            namespace_project_build_path(@subject.project.namespace,
+                                         @subject.project,
+                                         @subject.pipeline)
+          end
+
+          def action_type
+            case
+            when @subject.playable? then :playable
+            when @subject.active? then :cancel
+            when @subject.retryable? then :retry
+            end
+          end
+
+          def has_action?(current_user)
+            action_type && can?(current_user, :update_build, @subject)
+          end
+
+          def action_icon
+            case action_type
+            when :playable then 'remove'
+            when :cancel then 'icon_play'
+            when :retry then 'repeat'
+            end
+          end
+
+          def action_path
+            case action_type
+            when :playable
+              play_namespace_project_build_path(subject.project.namespace, subject.project, subject)
+            when :cancel
+              cancel_namespace_project_build_path(subject.project.namespace, subject.project, subject)
+            when :retry
+              retry_namespace_project_build_path(subject.project.namespace, subject.project, subject)
+            end
+          end
+
+          def action_method
+            :post
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/factory.rb b/lib/gitlab/ci/status/build/factory.rb
new file mode 100644
index 0000000000000000000000000000000000000000..dd38e1418b67a5fdeaa6ef886727846d1f20c656
--- /dev/null
+++ b/lib/gitlab/ci/status/build/factory.rb
@@ -0,0 +1,15 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Factory < Status::Factory
+          private
+
+          def core_status
+            super.extend(Status::Build::Common)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb
index ce4108fdcf2ff8debdcc01e7b98c81d967d5b0b6..60c559248aa4de210ece997ea4273a79f9126c4e 100644
--- a/lib/gitlab/ci/status/core.rb
+++ b/lib/gitlab/ci/status/core.rb
@@ -34,15 +34,15 @@ module Gitlab
         end
 
         def has_details?
-          raise NotImplementedError
+          false
         end
 
         def details_path
           raise NotImplementedError
         end
 
-        def has_action?
-          raise NotImplementedError
+        def has_action?(_user = nil)
+          false
         end
 
         def action_icon
@@ -52,6 +52,10 @@ module Gitlab
         def action_path
           raise NotImplementedError
         end
+
+        def action_method
+          raise NotImplementedError
+        end
       end
     end
   end