summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_canceled.ico (renamed from app/assets/images/ci_favicons/icon_status_canceled.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_created.ico (renamed from app/assets/images/ci_favicons/icon_status_created.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_failed.ico (renamed from app/assets/images/ci_favicons/icon_status_failed.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_manual.ico (renamed from app/assets/images/ci_favicons/icon_status_manual.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_not_found.ico (renamed from app/assets/images/ci_favicons/icon_status_not_found.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_pending.ico (renamed from app/assets/images/ci_favicons/icon_status_pending.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_running.ico (renamed from app/assets/images/ci_favicons/icon_status_running.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_skipped.ico (renamed from app/assets/images/ci_favicons/icon_status_skipped.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_success.ico (renamed from app/assets/images/ci_favicons/icon_status_success.ico)bin5430 -> 5430 bytes
-rwxr-xr-xapp/assets/images/ci_favicons/favicon_status_warning.ico (renamed from app/assets/images/ci_favicons/icon_status_warning.ico)bin5430 -> 5430 bytes
-rw-r--r--app/assets/javascripts/ci_status_icons.js34
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js10
-rw-r--r--app/assets/javascripts/vue_pipelines_index/components/stage.js28
-rw-r--r--app/assets/stylesheets/pages/profile.scss59
-rw-r--r--app/models/project_services/chat_notification_service.rb2
-rw-r--r--app/serializers/status_entity.rb6
-rw-r--r--app/services/search/global_service.rb11
-rw-r--r--app/services/search/group_service.rb18
-rw-r--r--app/services/search_service.rb2
-rw-r--r--app/views/layouts/nav/_project.html.haml4
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_pipelines.html.haml3
-rw-r--r--app/views/shared/_user_callout.html.haml17
-rw-r--r--changelogs/unreleased/29595-customize-experience-callout.yml4
-rw-r--r--changelogs/unreleased/31009-disable-test-settings-on-services-when-repository-is-empty.yml4
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--spec/controllers/projects/builds_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb2
-rw-r--r--spec/javascripts/ci_status_icon_spec.js44
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js13
-rw-r--r--spec/javascripts/user_callout_spec.js1
-rw-r--r--spec/javascripts/vue_pipelines_index/stage_spec.js66
-rw-r--r--spec/models/project_services/chat_notification_service_spec.rb20
-rw-r--r--spec/serializers/build_serializer_spec.rb2
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb2
-rw-r--r--spec/services/search/global_service_spec.rb21
-rw-r--r--spec/services/search/group_service_spec.rb40
-rw-r--r--spec/views/layouts/nav/_project.html.haml_spec.rb37
39 files changed, 360 insertions, 98 deletions
diff --git a/app/assets/images/ci_favicons/icon_status_canceled.ico b/app/assets/images/ci_favicons/favicon_status_canceled.ico
index 5a19458f2a2..5a19458f2a2 100755
--- a/app/assets/images/ci_favicons/icon_status_canceled.ico
+++ b/app/assets/images/ci_favicons/favicon_status_canceled.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_created.ico b/app/assets/images/ci_favicons/favicon_status_created.ico
index 4dca9640cb3..4dca9640cb3 100755
--- a/app/assets/images/ci_favicons/icon_status_created.ico
+++ b/app/assets/images/ci_favicons/favicon_status_created.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_failed.ico b/app/assets/images/ci_favicons/favicon_status_failed.ico
index c961ff9a69b..c961ff9a69b 100755
--- a/app/assets/images/ci_favicons/icon_status_failed.ico
+++ b/app/assets/images/ci_favicons/favicon_status_failed.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_manual.ico b/app/assets/images/ci_favicons/favicon_status_manual.ico
index 5fbbc99ea7c..5fbbc99ea7c 100755
--- a/app/assets/images/ci_favicons/icon_status_manual.ico
+++ b/app/assets/images/ci_favicons/favicon_status_manual.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_not_found.ico b/app/assets/images/ci_favicons/favicon_status_not_found.ico
index 21afa9c72e6..21afa9c72e6 100755
--- a/app/assets/images/ci_favicons/icon_status_not_found.ico
+++ b/app/assets/images/ci_favicons/favicon_status_not_found.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_pending.ico b/app/assets/images/ci_favicons/favicon_status_pending.ico
index 8be32dab85a..8be32dab85a 100755
--- a/app/assets/images/ci_favicons/icon_status_pending.ico
+++ b/app/assets/images/ci_favicons/favicon_status_pending.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_running.ico b/app/assets/images/ci_favicons/favicon_status_running.ico
index f328ff1a5ed..f328ff1a5ed 100755
--- a/app/assets/images/ci_favicons/icon_status_running.ico
+++ b/app/assets/images/ci_favicons/favicon_status_running.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_skipped.ico b/app/assets/images/ci_favicons/favicon_status_skipped.ico
index b4394e1b4af..b4394e1b4af 100755
--- a/app/assets/images/ci_favicons/icon_status_skipped.ico
+++ b/app/assets/images/ci_favicons/favicon_status_skipped.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_success.ico b/app/assets/images/ci_favicons/favicon_status_success.ico
index 4f436c95242..4f436c95242 100755
--- a/app/assets/images/ci_favicons/icon_status_success.ico
+++ b/app/assets/images/ci_favicons/favicon_status_success.ico
Binary files differ
diff --git a/app/assets/images/ci_favicons/icon_status_warning.ico b/app/assets/images/ci_favicons/favicon_status_warning.ico
index 805cc20cdec..805cc20cdec 100755
--- a/app/assets/images/ci_favicons/icon_status_warning.ico
+++ b/app/assets/images/ci_favicons/favicon_status_warning.ico
Binary files differ
diff --git a/app/assets/javascripts/ci_status_icons.js b/app/assets/javascripts/ci_status_icons.js
new file mode 100644
index 00000000000..f16616873b2
--- /dev/null
+++ b/app/assets/javascripts/ci_status_icons.js
@@ -0,0 +1,34 @@
+import CANCELED_SVG from 'icons/_icon_status_canceled_borderless.svg';
+import CREATED_SVG from 'icons/_icon_status_created_borderless.svg';
+import FAILED_SVG from 'icons/_icon_status_failed_borderless.svg';
+import MANUAL_SVG from 'icons/_icon_status_manual_borderless.svg';
+import PENDING_SVG from 'icons/_icon_status_pending_borderless.svg';
+import RUNNING_SVG from 'icons/_icon_status_running_borderless.svg';
+import SKIPPED_SVG from 'icons/_icon_status_skipped_borderless.svg';
+import SUCCESS_SVG from 'icons/_icon_status_success_borderless.svg';
+import WARNING_SVG from 'icons/_icon_status_warning_borderless.svg';
+
+const StatusIconEntityMap = {
+ icon_status_canceled: CANCELED_SVG,
+ icon_status_created: CREATED_SVG,
+ icon_status_failed: FAILED_SVG,
+ icon_status_manual: MANUAL_SVG,
+ icon_status_pending: PENDING_SVG,
+ icon_status_running: RUNNING_SVG,
+ icon_status_skipped: SKIPPED_SVG,
+ icon_status_success: SUCCESS_SVG,
+ icon_status_warning: WARNING_SVG,
+};
+
+export {
+ CANCELED_SVG,
+ CREATED_SVG,
+ FAILED_SVG,
+ MANUAL_SVG,
+ PENDING_SVG,
+ RUNNING_SVG,
+ SKIPPED_SVG,
+ SUCCESS_SVG,
+ WARNING_SVG,
+ StatusIconEntityMap as default,
+};
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 33c900e264b..01c4b9821d3 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -368,9 +368,9 @@
});
};
- w.gl.utils.setFavicon = (iconName) => {
- if (faviconEl && iconName) {
- faviconEl.setAttribute('href', `/assets/${iconName}.ico`);
+ w.gl.utils.setFavicon = (faviconPath) => {
+ if (faviconEl && faviconPath) {
+ faviconEl.setAttribute('href', faviconPath);
}
};
@@ -385,8 +385,8 @@
url: pageUrl,
dataType: 'json',
success: function(data) {
- if (data && data.icon) {
- gl.utils.setFavicon(`ci_favicons/${data.icon}`);
+ if (data && data.favicon) {
+ gl.utils.setFavicon(data.favicon);
} else {
gl.utils.resetFavicon();
}
diff --git a/app/assets/javascripts/vue_pipelines_index/components/stage.js b/app/assets/javascripts/vue_pipelines_index/components/stage.js
index a2c29002707..b8cc3630611 100644
--- a/app/assets/javascripts/vue_pipelines_index/components/stage.js
+++ b/app/assets/javascripts/vue_pipelines_index/components/stage.js
@@ -1,32 +1,11 @@
/* global Flash */
-import canceledSvg from 'icons/_icon_status_canceled_borderless.svg';
-import createdSvg from 'icons/_icon_status_created_borderless.svg';
-import failedSvg from 'icons/_icon_status_failed_borderless.svg';
-import manualSvg from 'icons/_icon_status_manual_borderless.svg';
-import pendingSvg from 'icons/_icon_status_pending_borderless.svg';
-import runningSvg from 'icons/_icon_status_running_borderless.svg';
-import skippedSvg from 'icons/_icon_status_skipped_borderless.svg';
-import successSvg from 'icons/_icon_status_success_borderless.svg';
-import warningSvg from 'icons/_icon_status_warning_borderless.svg';
+import StatusIconEntityMap from '../../ci_status_icons';
export default {
data() {
- const svgsDictionary = {
- icon_status_canceled: canceledSvg,
- icon_status_created: createdSvg,
- icon_status_failed: failedSvg,
- icon_status_manual: manualSvg,
- icon_status_pending: pendingSvg,
- icon_status_running: runningSvg,
- icon_status_skipped: skippedSvg,
- icon_status_success: successSvg,
- icon_status_warning: warningSvg,
- };
-
return {
builds: '',
spinner: '<span class="fa fa-spinner fa-spin"></span>',
- svg: svgsDictionary[this.stage.status.icon],
};
},
@@ -89,6 +68,9 @@ export default {
triggerButtonClass() {
return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
},
+ svgHTML() {
+ return StatusIconEntityMap[this.stage.status.icon];
+ },
},
template: `
<div>
@@ -100,7 +82,7 @@ export default {
data-toggle="dropdown"
type="button"
:aria-label="stage.title">
- <span v-html="svg" aria-hidden="true"></span>
+ <span v-html="svgHTML" aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 8c6dd392865..fe084eb9397 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -289,8 +289,12 @@ table.u2f-registrations {
margin: 0 auto;
.bordered-box {
- border: 1px solid $border-color;
+ border: 1px solid $blue-300;
border-radius: $border-radius-default;
+ background-color: $blue-25;
+ position: relative;
+ display: flex;
+ justify-content: center;
}
.landing {
@@ -298,28 +302,59 @@ table.u2f-registrations {
margin-bottom: $gl-padding;
.close {
- margin-right: 20px;
- }
+ position: absolute;
+ right: 20px;
+ opacity: 1;
+
+ .dismiss-icon {
+ float: right;
+ cursor: pointer;
+ color: $blue-300;
+ }
- .dismiss-icon {
- float: right;
- cursor: pointer;
- color: $cycle-analytics-dismiss-icon-color;
+ &:hover {
+ background-color: transparent;
+ border: 0;
+
+ .dismiss-icon {
+ color: $blue-400;
+ }
+ }
}
.svg-container {
- text-align: center;
+ margin-right: 30px;
+ display: inline-block;
svg {
- width: 136px;
- height: 136px;
+ height: 110px;
+ vertical-align: top;
}
}
+
+ .user-callout-copy {
+ display: inline-block;
+ vertical-align: top;
+ }
}
@media(max-width: $screen-xs-max) {
- .inner-content {
- padding-left: 30px;
+ text-align: center;
+
+ .bordered-box {
+ display: block;
+ }
+
+ .landing {
+ .svg-container,
+ .user-callout-copy {
+ margin: 0;
+ display: block;
+
+ svg {
+ height: 75px;
+ }
+ }
}
}
}
diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb
index fa782c6fbb7..f2dfb87dbda 100644
--- a/app/models/project_services/chat_notification_service.rb
+++ b/app/models/project_services/chat_notification_service.rb
@@ -22,7 +22,7 @@ class ChatNotificationService < Service
end
def can_test?
- valid?
+ super && valid?
end
def self.supported_events
diff --git a/app/serializers/status_entity.rb b/app/serializers/status_entity.rb
index dfd9d1584a1..944472f3e51 100644
--- a/app/serializers/status_entity.rb
+++ b/app/serializers/status_entity.rb
@@ -1,8 +1,12 @@
class StatusEntity < Grape::Entity
include RequestAwareEntity
- expose :icon, :favicon, :text, :label, :group
+ expose :icon, :text, :label, :group
expose :has_details?, as: :has_details
expose :details_path
+
+ expose :favicon do |status|
+ ActionController::Base.helpers.image_path(File.join('ci_favicons', "#{status.favicon}.ico"))
+ end
end
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index 8409b592b72..ff188102b62 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -7,16 +7,13 @@ module Search
end
def execute
- group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
- projects = ProjectsFinder.new(current_user: current_user).execute
-
- if group
- projects = projects.inside_path(group.full_path)
- end
-
Gitlab::SearchResults.new(current_user, projects, params[:search])
end
+ def projects
+ @projects ||= ProjectsFinder.new(current_user: current_user).execute
+ end
+
def scope
@scope ||= begin
allowed_scopes = %w[issues merge_requests milestones]
diff --git a/app/services/search/group_service.rb b/app/services/search/group_service.rb
new file mode 100644
index 00000000000..29478e3251f
--- /dev/null
+++ b/app/services/search/group_service.rb
@@ -0,0 +1,18 @@
+module Search
+ class GroupService < Search::GlobalService
+ attr_accessor :group
+
+ def initialize(user, group, params)
+ super(user, params)
+
+ @group = group
+ end
+
+ def projects
+ return Project.none unless group
+ return @projects if defined? @projects
+
+ @projects = super.inside_path(group.full_path)
+ end
+ end
+end
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index 8d46a8dab3e..22736c71725 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -54,6 +54,8 @@ class SearchService
Search::ProjectService.new(project, current_user, params)
elsif show_snippets?
Search::SnippetService.new(current_user, params)
+ elsif group
+ Search::GroupService.new(current_user, group, params)
else
Search::GlobalService.new(current_user, params)
end
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index e34cddeb3e2..37429c7cfc0 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -11,13 +11,13 @@
Project
- if project_nav_tab? :files
- = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases graphs network)) do
+ = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare projects/repositories tags branches releases graphs network)) do
= link_to project_files_path(@project), title: 'Repository', class: 'shortcuts-tree' do
%span
Repository
- if project_nav_tab? :container_registry
- = nav_link(controller: %w(container_registry)) do
+ = nav_link(controller: %w[projects/registry/repositories]) do
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
%span
Registry
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 03069804c86..da79ca2ee75 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -46,7 +46,7 @@
-# This tab is always loaded via AJAX
- if @pipelines.any?
#pipelines.pipelines.tab-pane
- = render 'projects/merge_requests/show/pipelines', endpoint: url_for(params.merge(format: :json))
+ = render 'projects/merge_requests/show/pipelines', endpoint: url_for(params.merge(format: :json)), disable_initialization: true
.mr-loading-status
= spinner
diff --git a/app/views/projects/merge_requests/show/_pipelines.html.haml b/app/views/projects/merge_requests/show/_pipelines.html.haml
index de4aa255bbd..2f1dbe87619 100644
--- a/app/views/projects/merge_requests/show/_pipelines.html.haml
+++ b/app/views/projects/merge_requests/show/_pipelines.html.haml
@@ -1,3 +1,4 @@
- endpoint_path = local_assigns[:endpoint] || pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :json)
+- disable_initialization = local_assigns.fetch(:disable_initialization, false)
-= render 'projects/commit/pipelines_list', endpoint: endpoint_path
+= render 'projects/commit/pipelines_list', endpoint: endpoint_path, disable_initialization: disable_initialization
diff --git a/app/views/shared/_user_callout.html.haml b/app/views/shared/_user_callout.html.haml
index 8f1293adcb1..8308baa7829 100644
--- a/app/views/shared/_user_callout.html.haml
+++ b/app/views/shared/_user_callout.html.haml
@@ -3,12 +3,11 @@
%button.btn.btn-default.close.js-close-callout{ type: 'button',
'aria-label' => 'Dismiss customize experience box' }
= icon('times', class: 'dismiss-icon', 'aria-hidden' => 'true')
- .row
- .col-sm-3.col-xs-12.svg-container
- = custom_icon('icon_customization')
- .col-sm-8.col-xs-12.inner-content
- %h4
- Customize your experience
- %p
- Change syntax themes, default project pages, and more in preferences.
- = link_to 'Check it out', profile_preferences_path, class: 'btn btn-default js-close-callout'
+ .svg-container
+ = custom_icon('icon_customization')
+ .user-callout-copy
+ %h4
+ Customize your experience
+ %p
+ Change syntax themes, default project pages, and more in preferences.
+ = link_to 'Check it out', profile_preferences_path, class: 'btn btn-primary js-close-callout'
diff --git a/changelogs/unreleased/29595-customize-experience-callout.yml b/changelogs/unreleased/29595-customize-experience-callout.yml
new file mode 100644
index 00000000000..ec8393142c6
--- /dev/null
+++ b/changelogs/unreleased/29595-customize-experience-callout.yml
@@ -0,0 +1,4 @@
+---
+title: 29595 Update callout design
+merge_request:
+author:
diff --git a/changelogs/unreleased/31009-disable-test-settings-on-services-when-repository-is-empty.yml b/changelogs/unreleased/31009-disable-test-settings-on-services-when-repository-is-empty.yml
new file mode 100644
index 00000000000..6e43a032f20
--- /dev/null
+++ b/changelogs/unreleased/31009-disable-test-settings-on-services-when-repository-is-empty.yml
@@ -0,0 +1,4 @@
+---
+title: Disable test settings on chat notification services when repository is empty
+merge_request: 10759
+author:
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index bcdf1b1faa8..c69676a1dac 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -15,7 +15,7 @@ module Gitlab
end
unless URI(address).scheme.in?(%w(tcp unix))
- raise "Unsupported Gitaly address: #{address.inspect}"
+ raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix'"
end
@addresses[name] = address
diff --git a/spec/controllers/projects/builds_controller_spec.rb b/spec/controllers/projects/builds_controller_spec.rb
index 13208d21918..faf3770f5e9 100644
--- a/spec/controllers/projects/builds_controller_spec.rb
+++ b/spec/controllers/projects/builds_controller_spec.rb
@@ -60,7 +60,7 @@ describe Projects::BuildsController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq status.favicon
+ expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
end
end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 1739d40ab88..cc393bd24f2 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -1208,7 +1208,7 @@ describe Projects::MergeRequestsController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq status.favicon
+ expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
end
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index d8f9bfd0d37..d9192177a06 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -86,7 +86,7 @@ describe Projects::PipelinesController do
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
expect(json_response['icon']).to eq status.icon
- expect(json_response['favicon']).to eq status.favicon
+ expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
end
end
end
diff --git a/spec/javascripts/ci_status_icon_spec.js b/spec/javascripts/ci_status_icon_spec.js
new file mode 100644
index 00000000000..c83416c15ef
--- /dev/null
+++ b/spec/javascripts/ci_status_icon_spec.js
@@ -0,0 +1,44 @@
+import * as icons from '~/ci_status_icons';
+
+describe('CI status icons', () => {
+ const statuses = [
+ 'canceled',
+ 'created',
+ 'failed',
+ 'manual',
+ 'pending',
+ 'running',
+ 'skipped',
+ 'success',
+ 'warning',
+ ];
+
+ statuses.forEach((status) => {
+ it(`should export a ${status} svg`, () => {
+ const key = `${status.toUpperCase()}_SVG`;
+
+ expect(Object.hasOwnProperty.call(icons, key)).toBe(true);
+ expect(icons[key]).toMatch(/^<svg/);
+ });
+ });
+
+ describe('default export map', () => {
+ const entityIconNames = [
+ 'icon_status_canceled',
+ 'icon_status_created',
+ 'icon_status_failed',
+ 'icon_status_manual',
+ 'icon_status_pending',
+ 'icon_status_running',
+ 'icon_status_skipped',
+ 'icon_status_success',
+ 'icon_status_warning',
+ ];
+
+ entityIconNames.forEach((iconName) => {
+ it(`should have a '${iconName}' key`, () => {
+ expect(Object.hasOwnProperty.call(icons.default, iconName)).toBe(true);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 03f3c206f44..56aabc16382 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -313,7 +313,7 @@ require('~/lib/utils/common_utils');
describe('gl.utils.setFavicon', () => {
it('should set page favicon to provided favicon', () => {
- const faviconName = 'custom_favicon';
+ const faviconPath = '//custom_favicon';
const fakeLink = {
setAttribute() {},
};
@@ -321,9 +321,9 @@ require('~/lib/utils/common_utils');
spyOn(window.document, 'getElementById').and.callFake(() => fakeLink);
spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => {
expect(attr).toEqual('href');
- expect(val.indexOf('/assets/custom_favicon.ico') > -1).toBe(true);
+ expect(val.indexOf(faviconPath) > -1).toBe(true);
});
- gl.utils.setFavicon(faviconName);
+ gl.utils.setFavicon(faviconPath);
});
});
@@ -345,13 +345,12 @@ require('~/lib/utils/common_utils');
describe('gl.utils.setCiStatusFavicon', () => {
it('should set page favicon to CI status favicon based on provided status', () => {
const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1/status.json`;
- const FAVICON_PATH = 'ci_favicons/';
- const FAVICON = 'icon_status_success';
+ const FAVICON_PATH = '//icon_status_success';
const spySetFavicon = spyOn(gl.utils, 'setFavicon').and.stub();
const spyResetFavicon = spyOn(gl.utils, 'resetFavicon').and.stub();
spyOn($, 'ajax').and.callFake(function (options) {
- options.success({ icon: FAVICON });
- expect(spySetFavicon).toHaveBeenCalledWith(FAVICON_PATH + FAVICON);
+ options.success({ favicon: FAVICON_PATH });
+ expect(spySetFavicon).toHaveBeenCalledWith(FAVICON_PATH);
options.success();
expect(spyResetFavicon).toHaveBeenCalled();
options.error();
diff --git a/spec/javascripts/user_callout_spec.js b/spec/javascripts/user_callout_spec.js
index c0375ebc61c..28d0c7dcd99 100644
--- a/spec/javascripts/user_callout_spec.js
+++ b/spec/javascripts/user_callout_spec.js
@@ -14,7 +14,6 @@ describe('UserCallout', function () {
this.userCallout = new UserCallout();
this.closeButton = $('.js-close-callout.close');
this.userCalloutBtn = $('.js-close-callout:not(.close)');
- this.userCalloutContainer = $('.user-callout');
});
it('hides when user clicks on the dismiss-icon', (done) => {
diff --git a/spec/javascripts/vue_pipelines_index/stage_spec.js b/spec/javascripts/vue_pipelines_index/stage_spec.js
new file mode 100644
index 00000000000..542661df2b0
--- /dev/null
+++ b/spec/javascripts/vue_pipelines_index/stage_spec.js
@@ -0,0 +1,66 @@
+import Vue from 'vue';
+import { SUCCESS_SVG } from '~/ci_status_icons';
+import Stage from '~/vue_pipelines_index/components/stage';
+
+function minify(string) {
+ return string.replace(/\s/g, '');
+}
+
+describe('Pipelines Stage', () => {
+ describe('data', () => {
+ let stageReturnValue;
+
+ beforeEach(() => {
+ stageReturnValue = Stage.data();
+ });
+
+ it('should return object with .builds and .spinner', () => {
+ expect(stageReturnValue).toEqual({
+ builds: '',
+ spinner: '<span class="fa fa-spinner fa-spin"></span>',
+ });
+ });
+ });
+
+ describe('computed', () => {
+ describe('svgHTML', function () {
+ let stage;
+ let svgHTML;
+
+ beforeEach(() => {
+ stage = { stage: { status: { icon: 'icon_status_success' } } };
+
+ svgHTML = Stage.computed.svgHTML.call(stage);
+ });
+
+ it("should return the correct icon for the stage's status", () => {
+ expect(svgHTML).toBe(SUCCESS_SVG);
+ });
+ });
+ });
+
+ describe('when mounted', () => {
+ let StageComponent;
+ let renderedComponent;
+ let stage;
+
+ beforeEach(() => {
+ stage = { status: { icon: 'icon_status_success' } };
+
+ StageComponent = Vue.extend(Stage);
+
+ renderedComponent = new StageComponent({
+ propsData: {
+ stage,
+ },
+ }).$mount();
+ });
+
+ it('should render the correct status svg', () => {
+ const minifiedComponent = minify(renderedComponent.$el.outerHTML);
+ const expectedSVG = minify(SUCCESS_SVG);
+
+ expect(minifiedComponent).toContain(expectedSVG);
+ });
+ });
+});
diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb
index c98e7ee14fd..592c90cda36 100644
--- a/spec/models/project_services/chat_notification_service_spec.rb
+++ b/spec/models/project_services/chat_notification_service_spec.rb
@@ -1,11 +1,29 @@
require 'spec_helper'
describe ChatNotificationService, models: true do
- describe "Associations" do
+ describe 'Associations' do
before do
allow(subject).to receive(:activated?).and_return(true)
end
it { is_expected.to validate_presence_of :webhook }
end
+
+ describe '#can_test?' do
+ context 'with empty repository' do
+ it 'returns false' do
+ subject.project = create(:empty_project, :empty_repo)
+
+ expect(subject.can_test?).to be false
+ end
+ end
+
+ context 'with repository' do
+ it 'returns true' do
+ subject.project = create(:project)
+
+ expect(subject.can_test?).to be true
+ end
+ end
+ end
end
diff --git a/spec/serializers/build_serializer_spec.rb b/spec/serializers/build_serializer_spec.rb
index 3cc791bca50..7f1abecfafe 100644
--- a/spec/serializers/build_serializer_spec.rb
+++ b/spec/serializers/build_serializer_spec.rb
@@ -38,7 +38,7 @@ describe BuildSerializer do
expect(subject[:text]).to eq(status.text)
expect(subject[:label]).to eq(status.label)
expect(subject[:icon]).to eq(status.icon)
- expect(subject[:favicon]).to eq(status.favicon)
+ expect(subject[:favicon]).to eq("/assets/ci_favicons/#{status.favicon}.ico")
end
end
end
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index f6249ab4664..ecde45a6d44 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -144,7 +144,7 @@ describe PipelineSerializer do
expect(subject[:text]).to eq(status.text)
expect(subject[:label]).to eq(status.label)
expect(subject[:icon]).to eq(status.icon)
- expect(subject[:favicon]).to eq(status.favicon)
+ expect(subject[:favicon]).to eq("/assets/ci_favicons/#{status.favicon}.ico")
end
end
end
diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb
index 2531607acad..cbf4f56213d 100644
--- a/spec/services/search/global_service_spec.rb
+++ b/spec/services/search/global_service_spec.rb
@@ -40,27 +40,6 @@ describe Search::GlobalService, services: true do
expect(results.objects('projects')).to match_array [found_project]
end
-
- context 'nested group' do
- let!(:nested_group) { create(:group, :nested) }
- let!(:project) { create(:empty_project, namespace: nested_group) }
-
- before do
- project.add_master(user)
- end
-
- it 'returns result from nested group' do
- results = Search::GlobalService.new(user, search: project.path).execute
-
- expect(results.objects('projects')).to match_array [project]
- end
-
- it 'returns result from descendants when search inside group' do
- results = Search::GlobalService.new(user, search: project.path, group_id: nested_group.parent).execute
-
- expect(results.objects('projects')).to match_array [project]
- end
- end
end
end
end
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
new file mode 100644
index 00000000000..38f264f6e7b
--- /dev/null
+++ b/spec/services/search/group_service_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Search::GroupService, services: true do
+ shared_examples_for 'group search' do
+ context 'finding projects by name' do
+ let(:user) { create(:user) }
+ let(:term) { "Project Name" }
+ let(:nested_group) { create(:group, :nested) }
+
+ # These projects shouldn't be found
+ let!(:outside_project) { create(:empty_project, :public, name: "Outside #{term}") }
+ let!(:private_project) { create(:empty_project, :private, namespace: nested_group, name: "Private #{term}" )}
+ let!(:other_project) { create(:empty_project, :public, namespace: nested_group, name: term.reverse) }
+
+ # These projects should be found
+ let!(:project1) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 1") }
+ let!(:project2) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 2") }
+ let!(:project3) { create(:empty_project, :internal, namespace: nested_group.parent, name: "Outer #{term}") }
+
+ let(:results) { Search::GroupService.new(user, search_group, search: term).execute }
+ subject { results.objects('projects') }
+
+ context 'in parent group' do
+ let(:search_group) { nested_group.parent }
+
+ it { is_expected.to match_array([project1, project2, project3]) }
+ end
+
+ context 'in subgroup' do
+ let(:search_group) { nested_group }
+
+ it { is_expected.to match_array([project1, project2]) }
+ end
+ end
+ end
+
+ describe 'basic search' do
+ include_examples 'group search'
+ end
+end
diff --git a/spec/views/layouts/nav/_project.html.haml_spec.rb b/spec/views/layouts/nav/_project.html.haml_spec.rb
new file mode 100644
index 00000000000..fd1637ca91b
--- /dev/null
+++ b/spec/views/layouts/nav/_project.html.haml_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe 'layouts/nav/_project' do
+ describe 'container registry tab' do
+ before do
+ stub_container_registry_config(enabled: true)
+
+ assign(:project, create(:project))
+ allow(view).to receive(:current_ref).and_return('master')
+
+ allow(view).to receive(:can?).and_return(true)
+ allow(controller).to receive(:controller_name)
+ .and_return('repositories')
+ allow(controller).to receive(:controller_path)
+ .and_return('projects/registry/repositories')
+ end
+
+ it 'has both Registry and Repository tabs' do
+ render
+
+ expect(rendered).to have_text 'Repository'
+ expect(rendered).to have_text 'Registry'
+ end
+
+ it 'highlights only one tab' do
+ render
+
+ expect(rendered).to have_css('.active', count: 1)
+ end
+
+ it 'highlights container registry tab only' do
+ render
+
+ expect(rendered).to have_css('.active', text: 'Registry')
+ end
+ end
+end