diff --git a/app/views/projects/jobs/_empty_state.html.haml b/app/views/projects/jobs/_empty_state.html.haml
index c66313bdbf3075260fafcf32b82eee1a303b32cf..311934d9c334484132cbba328608e2db1c23ded1 100644
--- a/app/views/projects/jobs/_empty_state.html.haml
+++ b/app/views/projects/jobs/_empty_state.html.haml
@@ -1,7 +1,7 @@
 - illustration = local_assigns.fetch(:illustration)
 - illustration_size = local_assigns.fetch(:illustration_size)
 - title = local_assigns.fetch(:title)
-- content = local_assigns.fetch(:content)
+- content = local_assigns.fetch(:content, nil)
 - action = local_assigns.fetch(:action, nil)
 
 .row.empty-state
@@ -11,7 +11,8 @@
   .col-xs-12
     .text-content
       %h4.text-center= title
-      %p= content
+      - if content
+        %p= content
       - if action
         .text-center
           = action
diff --git a/app/views/projects/jobs/_empty_states.html.haml b/app/views/projects/jobs/_empty_states.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e5198d047dfc8db4731a9c84c1ddfeb5a73648e2
--- /dev/null
+++ b/app/views/projects/jobs/_empty_states.html.haml
@@ -0,0 +1,9 @@
+- detailed_status = @build.detailed_status(current_user)
+- illustration = detailed_status.illustration
+
+= render 'empty_state',
+    illustration: illustration[:image],
+    illustration_size: illustration[:size],
+    title: illustration[:title],
+    content: illustration[:content],
+    action: detailed_status.has_action? ? link_to(detailed_status.action_button_title, detailed_status.action_path, method: detailed_status.action_method, class: 'btn btn-primary', title: detailed_status.action_button_title) : nil
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index dece4dfe16719ff95122695aaa50d29a5e90bad7..8beb4ffef45a069df667cd20c50dbab52c84f576 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -54,7 +54,8 @@
             Job has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)}
           - else
             Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
-    - if @build.started?
+
+    - if @build.has_trace?
       .build-trace-container.prepend-top-default
         .top-bar.js-top-bar
           .js-truncated-info.truncated-info.hidden-xs.pull-left.hidden<
@@ -88,25 +89,9 @@
         %pre.build-trace#build-trace
           %code.bash.js-build-output
           .build-loader-animation.js-build-refresh
-    - elsif @build.playable?
-      = render 'empty_state',
-        illustration: 'illustrations/manual_action.svg',
-        illustration_size: 'svg-394',
-        title: _('This job requires a manual action'),
-        content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments'),
-        action: ( link_to _('Trigger this manual action'), play_project_job_path(@project, @build), method: :post, class: 'btn btn-primary', title: _('Trigger this manual action') )
-    - elsif @build.created?
-      = render 'empty_state',
-        illustration: 'illustrations/job_not_triggered.svg',
-        illustration_size: 'svg-306',
-        title: _('This job has not been triggered yet'),
-        content: _('This job depends on upstream jobs that need to succeed in order for this job to be triggered')
     - else
-      = render 'empty_state',
-        illustration: 'illustrations/pending_job_empty.svg',
-        illustration_size: 'svg-430',
-        title: _('This job has not started yet'),
-        content: _('This job is in pending state and is waiting to be picked by a runner')
+      = render "empty_states"
+
   = render "sidebar", builds: @builds
 
 .js-build-options{ data: javascript_build_options }
diff --git a/changelogs/unreleased/42568-pipeline-empty-state.yml b/changelogs/unreleased/42568-pipeline-empty-state.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d36edcf1b373ef65ac3e00af9a800832a6c1a05a
--- /dev/null
+++ b/changelogs/unreleased/42568-pipeline-empty-state.yml
@@ -0,0 +1,5 @@
+---
+title: Improve empty state for canceled job
+merge_request: 17646
+author:
+type: fixed
diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb
index a3e4459f169c0e80c481a4b595d22f117dc5f2b1..f5950145348fccd7d04c59037b67ba6bff8aa387 100644
--- a/features/steps/shared/builds.rb
+++ b/features/steps/shared/builds.rb
@@ -11,7 +11,7 @@ module SharedBuilds
 
   step 'project has a recent build' do
     @pipeline = create(:ci_empty_pipeline, project: @project, sha: @project.commit.sha, ref: 'master')
-    @build = create(:ci_build, :running, :coverage, pipeline: @pipeline)
+    @build = create(:ci_build, :running, :coverage, :trace_artifact, pipeline: @pipeline)
   end
 
   step 'recent build is successful' do
diff --git a/lib/gitlab/ci/status/build/cancelable.rb b/lib/gitlab/ci/status/build/cancelable.rb
index 2d9166d6bdd54ff16882492f10b65085f183bd20..024047d498368964c6f7dd3457078bf92d96b223 100644
--- a/lib/gitlab/ci/status/build/cancelable.rb
+++ b/lib/gitlab/ci/status/build/cancelable.rb
@@ -23,6 +23,10 @@ def action_title
             'Cancel'
           end
 
+          def action_button_title
+            _('Cancel this job')
+          end
+
           def self.matches?(build, user)
             build.cancelable?
           end
diff --git a/lib/gitlab/ci/status/build/canceled.rb b/lib/gitlab/ci/status/build/canceled.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c83e2734a735dab7cc5b55059dfe91b628a670bc
--- /dev/null
+++ b/lib/gitlab/ci/status/build/canceled.rb
@@ -0,0 +1,21 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Canceled < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/canceled-job_empty.svg',
+              size: 'svg-430',
+              title: _('This job has been canceled')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.canceled?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/created.rb b/lib/gitlab/ci/status/build/created.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5be8e9de425ef93d02e4bfb4bc436f02cf07a8f3
--- /dev/null
+++ b/lib/gitlab/ci/status/build/created.rb
@@ -0,0 +1,22 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Created < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/job_not_triggered.svg',
+              size: 'svg-306',
+              title: _('This job has not been triggered yet'),
+              content: _('This job depends on upstream jobs that need to succeed in order for this job to be triggered')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.created?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/erased.rb b/lib/gitlab/ci/status/build/erased.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3a5113b16b65a68bff5dc4f49f44e3aff6139040
--- /dev/null
+++ b/lib/gitlab/ci/status/build/erased.rb
@@ -0,0 +1,21 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Erased < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/skipped-job_empty.svg',
+              size: 'svg-430',
+              title: _('Job has been erased')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.erased?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/factory.rb b/lib/gitlab/ci/status/build/factory.rb
index 20a319caf867212d11162e33c45bfa58711afa7f..2b26ebb45a1bff99932ec7e7b6f5f6c8ab119bce 100644
--- a/lib/gitlab/ci/status/build/factory.rb
+++ b/lib/gitlab/ci/status/build/factory.rb
@@ -4,7 +4,13 @@ module Status
       module Build
         class Factory < Status::Factory
           def self.extended_statuses
-            [[Status::Build::Cancelable,
+            [[Status::Build::Erased,
+              Status::Build::Manual,
+              Status::Build::Canceled,
+              Status::Build::Created,
+              Status::Build::Pending,
+              Status::Build::Skipped],
+             [Status::Build::Cancelable,
               Status::Build::Retryable],
              [Status::Build::Failed],
              [Status::Build::FailedAllowed,
diff --git a/lib/gitlab/ci/status/build/manual.rb b/lib/gitlab/ci/status/build/manual.rb
new file mode 100644
index 0000000000000000000000000000000000000000..042da6392d396691fbc8d6e49b6801de7d75f354
--- /dev/null
+++ b/lib/gitlab/ci/status/build/manual.rb
@@ -0,0 +1,22 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Manual < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/manual_action.svg',
+              size: 'svg-394',
+              title: _('This job requires a manual action'),
+              content: _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.playable?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/pending.rb b/lib/gitlab/ci/status/build/pending.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9dd9a27ad57401740344f6218f7dc3c792b37176
--- /dev/null
+++ b/lib/gitlab/ci/status/build/pending.rb
@@ -0,0 +1,22 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Pending < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/pending_job_empty.svg',
+              size: 'svg-430',
+              title: _('This job has not started yet'),
+              content: _('This job is in pending state and is waiting to be picked by a runner')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.pending?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/play.rb b/lib/gitlab/ci/status/build/play.rb
index b7b45466d3b471e375861882187bb8f20723043e..a8b9ebf08033c9a787db5a3a5eaa2f0474316a36 100644
--- a/lib/gitlab/ci/status/build/play.rb
+++ b/lib/gitlab/ci/status/build/play.rb
@@ -19,6 +19,10 @@ def action_title
             'Play'
           end
 
+          def action_button_title
+            _('Trigger this manual action')
+          end
+
           def action_path
             play_project_job_path(subject.project, subject)
           end
diff --git a/lib/gitlab/ci/status/build/retryable.rb b/lib/gitlab/ci/status/build/retryable.rb
index 44ffe783e50270f204b44a14ec58a594067b5b14..5aeb8e51480192dde6c529befb88601f96fb30b5 100644
--- a/lib/gitlab/ci/status/build/retryable.rb
+++ b/lib/gitlab/ci/status/build/retryable.rb
@@ -15,6 +15,10 @@ def action_title
             'Retry'
           end
 
+          def action_button_title
+            _('Retry this job')
+          end
+
           def action_path
             retry_project_job_path(subject.project, subject)
           end
diff --git a/lib/gitlab/ci/status/build/skipped.rb b/lib/gitlab/ci/status/build/skipped.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3e678d0baee824abdea387ae7864e83b73d3df77
--- /dev/null
+++ b/lib/gitlab/ci/status/build/skipped.rb
@@ -0,0 +1,21 @@
+module Gitlab
+  module Ci
+    module Status
+      module Build
+        class Skipped < Status::Extended
+          def illustration
+            {
+              image: 'illustrations/skipped-job_empty.svg',
+              size: 'svg-430',
+              title: _('This job has been skipped')
+            }
+          end
+
+          def self.matches?(build, user)
+            build.skipped?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/ci/status/build/stop.rb b/lib/gitlab/ci/status/build/stop.rb
index 46e730797e4fd77db7c2010cec69049572a95442..dea838bfa3928a772b8fbc6e55dff6dc12d30d53 100644
--- a/lib/gitlab/ci/status/build/stop.rb
+++ b/lib/gitlab/ci/status/build/stop.rb
@@ -19,6 +19,10 @@ def action_title
             'Stop'
           end
 
+          def action_button_title
+            _('Stop this environment')
+          end
+
           def action_path
             play_project_job_path(subject.project, subject)
           end
diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb
index daab6bb2de5a717d44aad84b6c5ac1cbe84be7d7..9d6a2f51c11363eb05d5e32507459db219f19e20 100644
--- a/lib/gitlab/ci/status/core.rb
+++ b/lib/gitlab/ci/status/core.rb
@@ -22,6 +22,10 @@ def favicon
           raise NotImplementedError
         end
 
+        def illustration
+          raise NotImplementedError
+        end
+
         def label
           raise NotImplementedError
         end
@@ -58,6 +62,10 @@ def action_title
           raise NotImplementedError
         end
 
+        def action_button_title
+          raise NotImplementedError
+        end
+
         # Hint that appears on all the pipeline graph tooltips and builds on the right sidebar in Job detail view
         def status_tooltip
           label
diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
index a43ba05c64c6971380b96b46a1f7b3b124442053..fd1629746ef4a2cfd38418b54c42b5e7048dd35c 100644
--- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb
@@ -9,6 +9,7 @@
 
   before do
     build.run
+    build.trace.set('hello')
     sign_in(user)
     visit_merge_request
   end
@@ -26,15 +27,15 @@ def visit_merge_request(format: :html, serializer: nil)
     let(:artifacts_file2) { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') }
 
     before do
-      create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file1)
-      create(:ci_build, pipeline: pipeline, when: 'manual')
+      create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1)
+      create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
     end
 
     it 'avoids repeated database queries' do
       before = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
 
-      create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file2)
-      create(:ci_build, pipeline: pipeline, when: 'manual')
+      create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file2)
+      create(:ci_build, :manual, pipeline: pipeline, when: 'manual')
 
       after = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
 
diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb
index b7eee39052a6c559672971059d83c3947eba63e2..bff5bbe99afbecab2738f1b2fa809fd7bf5c9d4f 100644
--- a/spec/features/projects/jobs/user_browses_job_spec.rb
+++ b/spec/features/projects/jobs/user_browses_job_spec.rb
@@ -1,16 +1,15 @@
 require 'spec_helper'
 
 describe 'User browses a job', :js do
-  let!(:build) { create(:ci_build, :running, :coverage, pipeline: pipeline) }
-  let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
-  let(:project) { create(:project, :repository, namespace: user.namespace) }
   let(:user) { create(:user) }
+  let(:user_access_level) { :developer }
+  let(:project) { create(:project, :repository, namespace: user.namespace) }
+  let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
+  let!(:build) { create(:ci_build, :success, :trace_artifact, :coverage, pipeline: pipeline) }
 
   before do
     project.add_master(user)
     project.enable_ci
-    build.success
-    build.trace.set('job trace')
 
     sign_in(user)
 
@@ -21,7 +20,9 @@
     expect(page).to have_content("Job ##{build.id}")
     expect(page).to have_css('#build-trace')
 
-    accept_confirm { click_link('Erase') }
+    # scroll to the top of the page first
+    execute_script "window.scrollTo(0,0)"
+    accept_confirm { find('.js-erase-link').click }
 
     expect(page).to have_no_css('.artifacts')
     expect(build).not_to have_trace
@@ -36,7 +37,7 @@
   end
 
   context 'with a failed job' do
-    let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }
+    let!(:build) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) }
 
     it 'displays the failure reason' do
       within('.builds-container') do
@@ -47,7 +48,7 @@
   end
 
   context 'when a failed job has been retried' do
-    let!(:build) { create(:ci_build, :failed, :retried, pipeline: pipeline) }
+    let!(:build) { create(:ci_build, :failed, :retried, :trace_artifact, pipeline: pipeline) }
 
     it 'displays the failure reason and retried label' do
       within('.builds-container') do
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 5d311f2dde33deb4c4c60d3abd35c1547e620368..749a1b81872b00c42e68090204bd739aede36a88 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -113,7 +113,7 @@
 
   describe "GET /:project/jobs/:id" do
     context "Job from project" do
-      let(:job) { create(:ci_build, :success, pipeline: pipeline) }
+      let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline) }
 
       before do
         visit project_job_path(project, job)
@@ -136,7 +136,7 @@
     end
 
     context 'when job is not running', :js do
-      let(:job) { create(:ci_build, :success, pipeline: pipeline) }
+      let(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) }
 
       before do
         visit project_job_path(project, job)
@@ -153,7 +153,7 @@
       end
 
       context 'if job failed' do
-        let(:job) { create(:ci_build, :failed, pipeline: pipeline) }
+        let(:job) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) }
 
         before do
           visit project_job_path(project, job)
@@ -339,7 +339,7 @@
 
       context 'job is successfull and has deployment' do
         let(:deployment) { create(:deployment) }
-        let(:job) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
+        let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
 
         it 'shows a link for the job' do
           visit project_job_path(project, job)
@@ -349,7 +349,7 @@
       end
 
       context 'job is complete and not successful' do
-        let(:job) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) }
+        let(:job) { create(:ci_build, :failed, :trace_artifact, environment: environment.name, pipeline: pipeline) }
 
         it 'shows a link for the job' do
           visit project_job_path(project, job)
@@ -360,7 +360,7 @@
 
       context 'job creates a new deployment' do
         let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) }
-        let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
+        let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, pipeline: pipeline) }
 
         it 'shows a link to latest deployment' do
           visit project_job_path(project, job)
@@ -379,6 +379,7 @@
       end
 
       it 'shows manual action empty state' do
+        expect(page).to have_content(job.detailed_status(user).illustration[:title])
         expect(page).to have_content('This job requires a manual action')
         expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments')
         expect(page).to have_link('Trigger this manual action')
@@ -402,6 +403,7 @@
       end
 
       it 'shows empty state' do
+        expect(page).to have_content(job.detailed_status(user).illustration[:title])
         expect(page).to have_content('This job has not been triggered yet')
         expect(page).to have_content('This job depends on upstream jobs that need to succeed in order for this job to be triggered')
       end
@@ -415,10 +417,53 @@
       end
 
       it 'shows pending empty state' do
+        expect(page).to have_content(job.detailed_status(user).illustration[:title])
         expect(page).to have_content('This job has not started yet')
         expect(page).to have_content('This job is in pending state and is waiting to be picked by a runner')
       end
     end
+
+    context 'Canceled job' do
+      context 'with log' do
+        let(:job) { create(:ci_build, :canceled, :trace_artifact, pipeline: pipeline) }
+
+        before do
+          visit project_job_path(project, job)
+        end
+
+        it 'renders job log' do
+          expect(page).to have_selector('.js-build-output')
+        end
+      end
+
+      context 'without log' do
+        let(:job) { create(:ci_build, :canceled, pipeline: pipeline) }
+
+        before do
+          visit project_job_path(project, job)
+        end
+
+        it 'renders empty state' do
+          expect(page).to have_content(job.detailed_status(user).illustration[:title])
+          expect(page).not_to have_selector('.js-build-output')
+          expect(page).to have_content('This job has been canceled')
+        end
+      end
+    end
+
+    context 'Skipped job' do
+      let(:job) { create(:ci_build, :skipped, pipeline: pipeline) }
+
+      before do
+        visit project_job_path(project, job)
+      end
+
+      it 'renders empty state' do
+        expect(page).to have_content(job.detailed_status(user).illustration[:title])
+        expect(page).not_to have_selector('.js-build-output')
+        expect(page).to have_content('This job has been skipped')
+      end
+    end
   end
 
   describe "POST /:project/jobs/:id/cancel", :js do
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
index 3ef0b6817e99e298045f605b8f1f4ac4a4f0f80f..78d6fa65b5a69f58ad8efc82b0e375a622393564 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -90,6 +90,10 @@
     describe '#action_title' do
       it { expect(subject.action_title).to eq 'Cancel' }
     end
+
+    describe '#action_button_title' do
+      it { expect(subject.action_button_title).to eq 'Cancel this job' }
+    end
   end
 
   describe '.matches?' do
diff --git a/spec/lib/gitlab/ci/status/build/canceled_spec.rb b/spec/lib/gitlab/ci/status/build/canceled_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c6b5cc6877073272400ad9bf70c410d563fc3999
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/canceled_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Canceled do
+  let(:user) { create(:user) }
+
+  subject do
+    described_class.new(double('subject'))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title) }
+  end
+
+  describe '.matches?' do
+    subject {described_class.matches?(build, user) }
+
+    context 'when build is canceled' do
+      let(:build) { create(:ci_build, :canceled) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not canceled' do
+      let(:build) { create(:ci_build) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/created_spec.rb b/spec/lib/gitlab/ci/status/build/created_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8bdfe6ef7a2cd5021db650cfbd09c70a3233b01a
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/created_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Created do
+  let(:user) { create(:user) }
+
+  subject do
+    described_class.new(double('subject'))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+  end
+
+  describe '.matches?' do
+    subject {described_class.matches?(build, user) }
+
+    context 'when build is created' do
+      let(:build) { create(:ci_build, :created) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not created' do
+      let(:build) { create(:ci_build) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/erased_spec.rb b/spec/lib/gitlab/ci/status/build/erased_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0acd271e375f4abb5aa9a2d5f1eb527a97950570
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/erased_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Erased do
+  let(:user) { create(:user) }
+
+  subject do
+    described_class.new(double('subject'))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title) }
+  end
+
+  describe '.matches?' do
+    subject { described_class.matches?(build, user) }
+
+    context 'when build is erased' do
+      let(:build) { create(:ci_build, :success, :erased) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not erased' do
+      let(:build) { create(:ci_build, :success, :trace_artifact) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index bbfa60169a1ce0a68fd4ec0ae00853cc28742222..6d5b73bb01b013c60d7910ecc9ff9eb3b11326bb 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -13,7 +13,7 @@
   end
 
   context 'when build is successful' do
-    let(:build) { create(:ci_build, :success) }
+    let(:build) { create(:ci_build, :success, :trace_artifact) }
 
     it 'matches correct core status' do
       expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
@@ -38,6 +38,33 @@
     end
   end
 
+  context 'when build is erased' do
+    let(:build) { create(:ci_build, :success, :erased) }
+
+    it 'matches correct core status' do
+      expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+    end
+
+    it 'matches correct extended statuses' do
+      expect(factory.extended_statuses)
+        .to eq [Gitlab::Ci::Status::Build::Erased,
+                Gitlab::Ci::Status::Build::Retryable]
+    end
+
+    it 'fabricates a retryable build status' do
+      expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+    end
+
+    it 'fabricates status with correct details' do
+      expect(status.text).to eq 'passed'
+      expect(status.icon).to eq 'status_success'
+      expect(status.favicon).to eq 'favicon_status_success'
+      expect(status.label).to eq 'passed'
+      expect(status).to have_details
+      expect(status).to have_action
+    end
+  end
+
   context 'when build is failed' do
     context 'when build is not allowed to fail' do
       let(:build) { create(:ci_build, :failed) }
@@ -106,7 +133,7 @@
 
     it 'matches correct extended statuses' do
       expect(factory.extended_statuses)
-        .to eq [Gitlab::Ci::Status::Build::Retryable]
+        .to eq [Gitlab::Ci::Status::Build::Canceled, Gitlab::Ci::Status::Build::Retryable]
     end
 
     it 'fabricates a retryable build status' do
@@ -117,6 +144,7 @@
       expect(status.text).to eq 'canceled'
       expect(status.icon).to eq 'status_canceled'
       expect(status.favicon).to eq 'favicon_status_canceled'
+      expect(status.illustration).to include(:image, :size, :title)
       expect(status.label).to eq 'canceled'
       expect(status).to have_details
       expect(status).to have_action
@@ -158,7 +186,7 @@
 
     it 'matches correct extended statuses' do
       expect(factory.extended_statuses)
-        .to eq [Gitlab::Ci::Status::Build::Cancelable]
+        .to eq [Gitlab::Ci::Status::Build::Pending, Gitlab::Ci::Status::Build::Cancelable]
     end
 
     it 'fabricates a cancelable build status' do
@@ -169,6 +197,7 @@
       expect(status.text).to eq 'pending'
       expect(status.icon).to eq 'status_pending'
       expect(status.favicon).to eq 'favicon_status_pending'
+      expect(status.illustration).to include(:image, :size, :title, :content)
       expect(status.label).to eq 'pending'
       expect(status).to have_details
       expect(status).to have_action
@@ -182,18 +211,19 @@
       expect(factory.core_status).to be_a Gitlab::Ci::Status::Skipped
     end
 
-    it 'does not match extended statuses' do
-      expect(factory.extended_statuses).to be_empty
+    it 'matches correct extended statuses' do
+      expect(factory.extended_statuses).to eq [Gitlab::Ci::Status::Build::Skipped]
     end
 
-    it 'fabricates a core skipped status' do
-      expect(status).to be_a Gitlab::Ci::Status::Skipped
+    it 'fabricates a skipped build status' do
+      expect(status).to be_a Gitlab::Ci::Status::Build::Skipped
     end
 
     it 'fabricates status with correct details' do
       expect(status.text).to eq 'skipped'
       expect(status.icon).to eq 'status_skipped'
       expect(status.favicon).to eq 'favicon_status_skipped'
+      expect(status.illustration).to include(:image, :size, :title)
       expect(status.label).to eq 'skipped'
       expect(status).to have_details
       expect(status).not_to have_action
@@ -210,7 +240,8 @@
 
       it 'matches correct extended statuses' do
         expect(factory.extended_statuses)
-          .to eq [Gitlab::Ci::Status::Build::Play,
+          .to eq [Gitlab::Ci::Status::Build::Manual,
+                  Gitlab::Ci::Status::Build::Play,
                   Gitlab::Ci::Status::Build::Action]
       end
 
@@ -223,6 +254,7 @@
         expect(status.group).to eq 'manual'
         expect(status.icon).to eq 'status_manual'
         expect(status.favicon).to eq 'favicon_status_manual'
+        expect(status.illustration).to include(:image, :size, :title, :content)
         expect(status.label).to include 'manual play action'
         expect(status).to have_details
         expect(status.action_path).to include 'play'
@@ -257,7 +289,8 @@
 
       it 'matches correct extended statuses' do
         expect(factory.extended_statuses)
-          .to eq [Gitlab::Ci::Status::Build::Stop,
+          .to eq [Gitlab::Ci::Status::Build::Manual,
+                  Gitlab::Ci::Status::Build::Stop,
                   Gitlab::Ci::Status::Build::Action]
       end
 
diff --git a/spec/lib/gitlab/ci/status/build/manual_spec.rb b/spec/lib/gitlab/ci/status/build/manual_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6386296f992bb8939a53548cf4f38effec62b5b6
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/manual_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Manual do
+  let(:user) { create(:user) }
+
+  subject do
+    build = create(:ci_build, :manual)
+    described_class.new(Gitlab::Ci::Status::Core.new(build, user))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+  end
+
+  describe '.matches?' do
+    subject {described_class.matches?(build, user) }
+
+    context 'when build is manual' do
+      let(:build) { create(:ci_build, :manual) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not manual' do
+      let(:build) { create(:ci_build) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/pending_spec.rb b/spec/lib/gitlab/ci/status/build/pending_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4cf70828e53d9e27dc87f2b8b7715d05889edfaf
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/pending_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Pending do
+  let(:user) { create(:user) }
+
+  subject do
+    described_class.new(double('subject'))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+  end
+
+  describe '.matches?' do
+    subject {described_class.matches?(build, user) }
+
+    context 'when build is pending' do
+      let(:build) { create(:ci_build, :pending) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not pending' do
+      let(:build) { create(:ci_build, :success) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
index 35e47cd252676f5c7263dbc377aebd4f24c6fb4f..f128c1d4ca48420f4082dd8a0711d0531efee8a6 100644
--- a/spec/lib/gitlab/ci/status/build/play_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -69,6 +69,10 @@
     it { expect(subject.action_title).to eq 'Play' }
   end
 
+  describe '#action_button_title' do
+    it { expect(subject.action_button_title).to eq 'Trigger this manual action' }
+  end
+
   describe '.matches?' do
     subject { described_class.matches?(build, user) }
 
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 0c5099b7da5bbc238838ce4647daf932136edb06..84d98588f2d72d0901e3e0a7e24fc3487e716072 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -90,6 +90,10 @@
     describe '#action_title' do
       it { expect(subject.action_title).to eq 'Retry' }
     end
+
+    describe '#action_button_title' do
+      it { expect(subject.action_button_title).to eq 'Retry this job' }
+    end
   end
 
   describe '.matches?' do
diff --git a/spec/lib/gitlab/ci/status/build/skipped_spec.rb b/spec/lib/gitlab/ci/status/build/skipped_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..46f6933025add2ca6bd4d3ae93aefc115ec330b0
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/skipped_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Skipped do
+  let(:user) { create(:user) }
+
+  subject do
+    described_class.new(double('subject'))
+  end
+
+  describe '#illustration' do
+    it { expect(subject.illustration).to include(:image, :size, :title) }
+  end
+
+  describe '.matches?' do
+    subject {described_class.matches?(build, user) }
+
+    context 'when build is skipped' do
+      let(:build) { create(:ci_build, :skipped) }
+
+      it 'is a correct match' do
+        expect(subject).to be true
+      end
+    end
+
+    context 'when build is not skipped' do
+      let(:build) { create(:ci_build) }
+
+      it 'does not match' do
+        expect(subject).to be false
+      end
+    end
+  end
+end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index f16fc5c9205c36ec4945577a613633319d3b9cbf..5b7534c96c1cf6aa2f09d5ea5d7efe38f9ff76d2 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -44,6 +44,10 @@
     describe '#action_title' do
       it { expect(subject.action_title).to eq 'Stop' }
     end
+
+    describe '#action_button_title' do
+      it { expect(subject.action_button_title).to eq 'Stop this environment' }
+    end
   end
 
   describe '.matches?' do
diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb
index 9e692159bd0d63a0adee6962a8c34a36a62582b9..c93152b88e30abd99833813617928a01aacdaa5a 100644
--- a/spec/views/projects/jobs/show.html.haml_spec.rb
+++ b/spec/views/projects/jobs/show.html.haml_spec.rb
@@ -21,7 +21,7 @@
   describe 'environment info in job view' do
     context 'job with latest deployment' do
       let(:build) do
-        create(:ci_build, :success, environment: 'staging')
+        create(:ci_build, :success, :trace_artifact, environment: 'staging')
       end
 
       before do
@@ -40,11 +40,11 @@
 
     context 'job with outdated deployment' do
       let(:build) do
-        create(:ci_build, :success, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline)
       end
 
       let(:second_build) do
-        create(:ci_build, :success, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline)
       end
 
       let(:environment) do
@@ -70,7 +70,7 @@
 
     context 'job failed to deploy' do
       let(:build) do
-        create(:ci_build, :failed, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline)
       end
 
       let!(:environment) do
@@ -88,7 +88,7 @@
 
     context 'job will deploy' do
       let(:build) do
-        create(:ci_build, :running, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline)
       end
 
       context 'when environment exists' do
@@ -136,7 +136,7 @@
 
     context 'job that failed to deploy and environment has not been created' do
       let(:build) do
-        create(:ci_build, :failed, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline)
       end
 
       let!(:environment) do
@@ -154,7 +154,7 @@
 
     context 'job that will deploy and environment has not been created' do
       let(:build) do
-        create(:ci_build, :running, environment: 'staging', pipeline: pipeline)
+        create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline)
       end
 
       let!(:environment) do
@@ -174,8 +174,9 @@
   end
 
   context 'when job is running' do
+    let(:build) { create(:ci_build, :trace_live, :running, pipeline: pipeline) }
+
     before do
-      build.run!
       render
     end