Further design iteration on project overview

Continues the iteration on the project overview UI:

- moved star, fork and new clone button
(copy SSH/HTTPS URLs) to top right,
  made them smaller
- avatar is now larger (64px)
- 'Request access' is now a link instead
  of a button
- overview comes before the description +
  changed styling and added icons
- description font-size is now 16px (large-paragraph)
- quick links to files are moved downwards
  below the commit/pipeline info
- margins changed to group content into
  4 groups to clean up the interface
- visibility info reduced to icon-only and
  moved to the right of the title
This commit is contained in:
Dennis Tang 2018-12-07 14:11:42 +00:00
parent 61d91f640b
commit 75496059a1
36 changed files with 673 additions and 488 deletions

View File

@ -12,6 +12,10 @@ export default function notificationsDropdown() {
const form = $(this).parents('.notification-form:first');
form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner');
if (form.hasClass('no-label')) {
form.find('.js-notification-loading').toggleClass('hidden');
form.find('.js-notifications-icon').toggleClass('hidden');
}
form.find('#notification_setting_level').val(notificationLevel);
form.submit();
});

View File

@ -13,6 +13,9 @@ export default class Project {
const $cloneOptions = $('ul.clone-options-dropdown');
const $projectCloneField = $('#project_clone');
const $cloneBtnLabel = $('.js-git-clone-holder .js-clone-dropdown-label');
const mobileCloneField = document.querySelector(
'.js-mobile-git-clone .js-clone-dropdown-label',
);
const selectedCloneOption = $cloneBtnLabel.text().trim();
if (selectedCloneOption.length > 0) {
@ -36,7 +39,11 @@ export default class Project {
$label.text(activeText);
});
$projectCloneField.val(url);
if (mobileCloneField) {
mobileCloneField.dataset.clipboardText = url;
} else {
$projectCloneField.val(url);
}
$('.js-git-empty .js-clone').text(url);
});
// Ref switcher

View File

@ -21,6 +21,7 @@
&.s46 { @include avatar-size(46px, 15px); }
&.s48 { @include avatar-size(48px, 10px); }
&.s60 { @include avatar-size(60px, 12px); }
&.s64 { @include avatar-size(64px, 14px); }
&.s70 { @include avatar-size(70px, 14px); }
&.s90 { @include avatar-size(90px, 15px); }
&.s100 { @include avatar-size(100px, 15px); }
@ -80,6 +81,7 @@
&.s40 { font-size: 16px; line-height: 38px; }
&.s48 { font-size: 20px; line-height: 46px; }
&.s60 { font-size: 32px; line-height: 58px; }
&.s64 { font-size: 32px; line-height: 64px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 88px; }
&.s100 { font-size: 36px; line-height: 98px; }

View File

@ -142,8 +142,14 @@
&.btn-sm {
padding: 4px 10px;
font-size: 13px;
line-height: 18px;
font-size: $gl-btn-small-font-size;
line-height: $gl-btn-small-line-height;
}
&.btn-xs {
padding: 2px $gl-btn-padding;
font-size: $gl-btn-small-font-size;
line-height: $gl-btn-small-line-height;
}
&.btn-success,

View File

@ -39,15 +39,6 @@
.git-clone-holder {
display: none;
}
// Display Star and Fork buttons without counters on mobile.
.project-repo-buttons {
display: block;
.count-buttons .count-badge {
margin-top: $gl-padding-8;
}
}
}
.group-buttons {

View File

@ -197,6 +197,7 @@ $well-light-text-color: #5b6169;
$gl-font-size: 14px;
$gl-font-size-xs: 11px;
$gl-font-size-small: 12px;
$gl-font-size-large: 16px;
$gl-font-weight-normal: 400;
$gl-font-weight-bold: 600;
$gl-text-color: #2e2e2e;
@ -270,7 +271,8 @@ $performance-bar-height: 35px;
$flash-height: 52px;
$context-header-height: 60px;
$breadcrumb-min-height: 48px;
$project-title-row-height: 24px;
$project-title-row-height: 64px;
$project-avatar-mobile-size: 24px;
$gl-line-height: 16px;
$gl-line-height-24: 24px;
@ -365,6 +367,8 @@ $gl-btn-padding: 10px;
$gl-btn-line-height: 16px;
$gl-btn-vert-padding: 8px;
$gl-btn-horz-padding: 12px;
$gl-btn-small-font-size: 13px;
$gl-btn-small-line-height: 13px;
/*
* Badges

View File

@ -144,7 +144,6 @@
.group-home-panel {
padding-top: 24px;
padding-bottom: 24px;
border-bottom: 1px solid $border-color;
.group-avatar {
float: none;
@ -155,7 +154,6 @@
}
}
.project-title,
.group-title {
margin-top: 10px;
margin-bottom: 10px;
@ -195,25 +193,69 @@
}
.project-home-panel {
padding-top: $gl-padding-8;
padding-bottom: $gl-padding-24;
.project-title-row {
margin-right: $gl-padding-8;
}
padding-top: $gl-padding;
padding-bottom: $gl-padding;
.project-avatar {
width: $project-title-row-height;
height: $project-title-row-height;
flex-shrink: 0;
flex-basis: $project-title-row-height;
margin: 0 $gl-padding-8 0 0;
margin: 0 $gl-padding 0 0;
}
.project-title {
margin-top: 8px;
margin-bottom: 5px;
font-size: 20px;
line-height: $project-title-row-height;
line-height: $gl-line-height-24;
font-weight: bold;
.icon {
font-size: $gl-font-size-large;
}
.project-visibility {
color: $gl-text-color-secondary;
}
.project-tag-list {
font-size: $gl-font-size;
font-weight: $gl-font-weight-normal;
.icon {
position: relative;
top: 3px;
margin-right: $gl-padding-4;
}
}
}
.project-title-row {
@include media-breakpoint-down(sm) {
.project-avatar {
width: $project-avatar-mobile-size;
height: $project-avatar-mobile-size;
flex-basis: $project-avatar-mobile-size;
.avatar {
font-size: 20px;
line-height: 46px;
}
}
.project-title {
margin-top: 4px;
margin-bottom: 2px;
font-size: $gl-font-size;
line-height: $gl-font-size-large;
}
.project-tag-list,
.project-metadata {
font-size: $gl-font-size-small;
}
}
}
.project-metadata {
@ -222,16 +264,6 @@
line-height: $gl-btn-line-height;
color: $gl-text-color-secondary;
.icon {
margin-right: $gl-padding-4;
font-size: 16px;
}
.project-visibility,
.project-license,
.project-tag-list {
margin-right: $gl-padding-8;
}
.project-license {
.btn {
@ -240,12 +272,22 @@
}
}
.project-tag-list,
.project-license {
.icon {
position: relative;
top: 2px;
}
.access-request-link,
.project-tag-list {
padding-left: $gl-padding-8;
border-left: 1px solid $gl-text-color-secondary;
}
}
.project-description {
@include media-breakpoint-up(md) {
font-size: $gl-font-size-large;
}
}
.notifications-btn {
.fa-bell {
margin-right: 0;
}
}
}
@ -298,14 +340,6 @@
vertical-align: top;
margin-top: $gl-padding;
.count-badge {
height: $input-height;
.icon {
top: -1px;
}
}
.count-badge-count,
.count-badge-button {
border: 1px solid $border-color;
@ -319,29 +353,25 @@
.count-badge-count {
padding: 0 12px;
border-right: 0;
border-radius: $border-radius-base 0 0 $border-radius-base;
background: $gray-light;
border-radius: 0 $border-radius-base $border-radius-base 0;
}
.count-badge-button {
border-radius: 0 $border-radius-base $border-radius-base 0;
border-right: 0;
border-radius: $border-radius-base 0 0 $border-radius-base;
}
}
.project-clone-holder {
display: inline-block;
margin: $gl-padding $gl-padding-8 0 0;
margin: $gl-padding 0 0;
input {
height: $input-height;
}
}
.clone-dropdown-btn {
background-color: $white-light;
}
.clone-options-dropdown {
min-width: 240px;
@ -355,6 +385,31 @@
}
}
.project-repo-buttons {
.icon {
top: 0;
}
.count-badge,
.btn-xs {
height: 24px;
}
.dropdown-toggle,
.clone-dropdown-btn {
.fa {
color: unset;
}
}
.btn {
.notifications-icon {
top: 1px;
margin-right: 0;
}
}
}
.split-one {
display: inline-table;
margin-right: 12px;
@ -715,10 +770,10 @@
border-bottom: 1px solid $border-color;
}
.project-stats {
.project-stats,
.project-buttons {
font-size: 0;
text-align: center;
border-bottom: 1px solid $border-color;
.scrolling-tabs-container {
.scrolling-tabs {
@ -786,23 +841,43 @@
font-size: $gl-font-size;
line-height: $gl-btn-line-height;
color: $gl-text-color-secondary;
white-space: nowrap;
white-space: pre-wrap;
}
.stat-link {
border-bottom: 0;
color: $black;
&:hover,
&:focus {
color: $gl-text-color;
text-decoration: underline;
border-bottom: 0;
}
.project-stat-value {
color: $gl-text-color;
}
.icon {
color: $gl-text-color-secondary;
}
.add-license-link {
&,
.icon {
color: $blue-600;
}
}
}
.btn {
padding: $gl-btn-vert-padding $gl-btn-horz-padding;
margin-top: $gl-padding;
padding: $gl-btn-vert-padding $gl-btn-padding;
line-height: $gl-btn-line-height;
.icon {
top: 0;
}
}
.btn-missing {
@ -811,6 +886,13 @@
}
}
.project-buttons {
.stat-text {
@extend .btn;
@extend .btn-default;
}
}
.repository-languages-bar {
height: 8px;
margin-bottom: $gl-padding-8;
@ -934,8 +1016,6 @@ pre.light-well {
}
.git-clone-holder {
width: 320px;
.btn-clipboard {
border: 1px solid $border-color;
}
@ -958,6 +1038,15 @@ pre.light-well {
}
}
.git-clone-holder,
.mobile-git-clone {
.btn {
.icon {
fill: $white;
}
}
}
.cannot-be-merged,
.cannot-be-merged:hover {
color: $red-500;

View File

@ -16,7 +16,11 @@ class NotificationSettingsController < ApplicationController
@notification_setting = current_user.notification_settings.find(params[:id])
@saved = @notification_setting.update(notification_setting_params_for(@notification_setting.source))
render_response
if params[:hide_label].present?
render_response("projects/buttons/_notifications")
else
render_response
end
end
private
@ -37,9 +41,9 @@ class NotificationSettingsController < ApplicationController
can?(current_user, ability_name, resource)
end
def render_response
def render_response(response_template = "shared/notifications/_button")
render json: {
html: view_to_html_string("shared/notifications/_button", notification_setting: @notification_setting),
html: view_to_html_string(response_template, notification_setting: @notification_setting),
saved: @saved
}
end

View File

@ -85,13 +85,14 @@ module ButtonHelper
dropdown_item_with_description('SSH', dropdown_description, href: append_url, data: { clone_type: 'ssh' })
end
def dropdown_item_with_description(title, description, href: nil, data: nil)
def dropdown_item_with_description(title, description, href: nil, data: nil, default: false)
active_class = "is-active" if default
button_content = content_tag(:strong, title, class: 'dropdown-menu-inner-title')
button_content << content_tag(:span, description, class: 'dropdown-menu-inner-content') if description
content_tag (href ? :a : :span),
(href ? button_content : title),
class: "#{title.downcase}-selector",
class: "#{title.downcase}-selector #{active_class}",
href: (href if href),
data: (data if data)
end

View File

@ -140,7 +140,7 @@ module VisibilityLevelHelper
end
def project_visibility_icon_description(level)
"#{project_visibility_level_description(level)}"
"#{visibility_level_label(level)} - #{project_visibility_level_description(level)}"
end
def visibility_level_label(level)

View File

@ -6,27 +6,27 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
include GitlabRoutingHelper
include StorageHelper
include TreeHelper
include IconsHelper
include ChecksCollaboration
include Gitlab::Utils::StrongMemoize
presents :project
AnchorData = Struct.new(:enabled, :label, :link, :class_modifier)
AnchorData = Struct.new(:is_link, :label, :link, :class_modifier, :icon)
MAX_TAGS_TO_SHOW = 3
def statistic_icon(icon_name = 'plus-square-o')
sprite_icon(icon_name, size: 16, css_class: 'icon append-right-4')
end
def statistics_anchors(show_auto_devops_callout:)
[
readme_anchor_data,
changelog_anchor_data,
contribution_guide_anchor_data,
files_anchor_data,
license_anchor_data,
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
gitlab_ci_anchor_data,
autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
kubernetes_cluster_anchor_data
].compact.select { |item| item.enabled }
files_anchor_data
].compact.select(&:is_link)
end
def statistics_buttons(show_auto_devops_callout:)
@ -37,27 +37,28 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
kubernetes_cluster_anchor_data,
gitlab_ci_anchor_data
].compact.reject { |item| item.enabled }
].compact.reject(&:is_link)
end
def empty_repo_statistics_anchors
[
files_anchor_data,
license_anchor_data,
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
autodevops_anchor_data,
kubernetes_cluster_anchor_data
].compact.select { |item| item.enabled }
files_anchor_data
].compact.select { |item| item.is_link }
end
def empty_repo_statistics_buttons
[
new_file_anchor_data,
readme_anchor_data,
changelog_anchor_data,
contribution_guide_anchor_data,
autodevops_anchor_data,
kubernetes_cluster_anchor_data
].compact.reject { |item| item.enabled }
].compact.reject { |item| item.is_link }
end
def default_view
@ -113,7 +114,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
end
def add_contribution_guide_path
add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide')
add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add CONTRIBUTING')
end
def add_ci_yml_path
@ -149,32 +150,52 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def files_anchor_data
AnchorData.new(true,
_('Files (%{human_size})') % { human_size: storage_counter(statistics.total_repository_size) },
statistic_icon('doc-code') +
_('%{strong_start}%{human_size}%{strong_end} Files').html_safe % {
human_size: storage_counter(statistics.total_repository_size),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_tree_path(project))
end
def commits_anchor_data
AnchorData.new(true,
n_('Commit (%{commit_count})', 'Commits (%{commit_count})', statistics.commit_count) % { commit_count: number_with_delimiter(statistics.commit_count) },
statistic_icon('commit') +
n_('%{strong_start}%{commit_count}%{strong_end} Commit', '%{strong_start}%{commit_count}%{strong_end} Commits', statistics.commit_count).html_safe % {
commit_count: number_with_delimiter(statistics.commit_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_commits_path(project, repository.root_ref))
end
def branches_anchor_data
AnchorData.new(true,
n_('Branch (%{branch_count})', 'Branches (%{branch_count})', repository.branch_count) % { branch_count: number_with_delimiter(repository.branch_count) },
statistic_icon('branch') +
n_('%{strong_start}%{branch_count}%{strong_end} Branch', '%{strong_start}%{branch_count}%{strong_end} Branches', repository.branch_count).html_safe % {
branch_count: number_with_delimiter(repository.branch_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_branches_path(project))
end
def tags_anchor_data
AnchorData.new(true,
n_('Tag (%{tag_count})', 'Tags (%{tag_count})', repository.tag_count) % { tag_count: number_with_delimiter(repository.tag_count) },
statistic_icon('label') +
n_('%{strong_start}%{tag_count}%{strong_end} Tag', '%{strong_start}%{tag_count}%{strong_end} Tags', repository.tag_count).html_safe % {
tag_count: number_with_delimiter(repository.tag_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_tags_path(project))
end
def new_file_anchor_data
if current_user && can_current_user_push_to_default_branch?
AnchorData.new(false,
_('New file'),
statistic_icon + _('New file'),
project_new_blob_path(project, default_branch || 'master'),
'success')
end
@ -183,40 +204,45 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def readme_anchor_data
if current_user && can_current_user_push_to_default_branch? && repository.readme.nil?
AnchorData.new(false,
_('Add Readme'),
statistic_icon + _('Add README'),
add_readme_path)
elsif repository.readme
AnchorData.new(true,
_('Readme'),
default_view != 'readme' ? readme_path : '#readme')
AnchorData.new(false,
statistic_icon('doc-text') + _('README'),
default_view != 'readme' ? readme_path : '#readme',
'default',
'doc-text')
end
end
def changelog_anchor_data
if current_user && can_current_user_push_to_default_branch? && repository.changelog.blank?
AnchorData.new(false,
_('Add Changelog'),
statistic_icon + _('Add CHANGELOG'),
add_changelog_path)
elsif repository.changelog.present?
AnchorData.new(true,
_('Changelog'),
changelog_path)
AnchorData.new(false,
statistic_icon('doc-text') + _('CHANGELOG'),
changelog_path,
'default')
end
end
def license_anchor_data
icon = statistic_icon('scale')
if repository.license_blob.present?
AnchorData.new(true,
license_short_name,
icon + content_tag(:strong, license_short_name, class: 'project-stat-value'),
license_path)
else
if current_user && can_current_user_push_to_default_branch?
AnchorData.new(false,
_('Add license'),
AnchorData.new(true,
content_tag(:span, icon + _('Add license'), class: 'add-license-link d-flex'),
add_license_path)
else
AnchorData.new(false,
_('No license. All rights reserved'),
AnchorData.new(true,
icon + content_tag(:strong, _('No license. All rights reserved'), class: 'project-stat-value'),
nil)
end
end
@ -225,22 +251,29 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def contribution_guide_anchor_data
if current_user && can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
AnchorData.new(false,
_('Add Contribution guide'),
statistic_icon + _('Add CONTRIBUTING'),
add_contribution_guide_path)
elsif repository.contribution_guide.present?
AnchorData.new(true,
_('Contribution guide'),
AnchorData.new(false,
statistic_icon('doc-text') + _('CONTRIBUTING'),
contribution_guide_path)
end
end
def autodevops_anchor_data(show_auto_devops_callout: false)
if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
AnchorData.new(auto_devops_enabled?,
auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
if auto_devops_enabled?
AnchorData.new(false,
statistic_icon('doc-text') + _('Auto DevOps enabled'),
project_settings_ci_cd_path(project, anchor: 'autodevops-settings'),
'default')
else
AnchorData.new(false,
statistic_icon + _('Enable Auto DevOps'),
project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
elsif auto_devops_enabled?
AnchorData.new(true,
AnchorData.new(false,
_('Auto DevOps enabled'),
nil)
end
@ -248,27 +281,32 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def kubernetes_cluster_anchor_data
if current_user && can?(current_user, :create_cluster, project)
cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
if clusters.empty?
cluster_link = new_project_cluster_path(project)
end
AnchorData.new(false,
statistic_icon + _('Add Kubernetes cluster'),
new_project_cluster_path(project))
else
cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
AnchorData.new(!clusters.empty?,
clusters.empty? ? _('Add Kubernetes cluster') : _('Kubernetes configured'),
cluster_link)
AnchorData.new(false,
_('Kubernetes configured'),
cluster_link,
'default')
end
end
end
def gitlab_ci_anchor_data
if current_user && can_current_user_push_code? && repository.gitlab_ci_yml.blank? && !auto_devops_enabled?
AnchorData.new(false,
_('Set up CI/CD'),
statistic_icon + _('Set up CI/CD'),
add_ci_yml_path)
elsif repository.gitlab_ci_yml.present?
AnchorData.new(true,
_('CI/CD configuration'),
ci_configuration_path)
AnchorData.new(false,
statistic_icon('doc-text') + _('CI/CD configuration'),
ci_configuration_path,
'default')
end
end

View File

@ -1,4 +1,4 @@
.group-home-panel.text-center
.group-home-panel.text-center.border-bottom
%div{ class: container_class }
.avatar-container.s70.group-avatar
= group_icon(@group, class: "avatar s70 avatar-tile")

View File

@ -1,7 +1,9 @@
- is_project_overview = local_assigns.fetch(:is_project_overview, false)
- commit = local_assigns.fetch(:commit) { @repository.commit }
- ref = local_assigns.fetch(:ref) { current_ref }
- project = local_assigns.fetch(:project) { @project }
- content_url = local_assigns.fetch(:content_url) { @tree.readme ? project_blob_path(@project, tree_join(@ref, @tree.readme.path)) : project_tree_path(@project, @ref) }
- show_auto_devops_callout = show_auto_devops_callout?(@project)
#tree-holder.tree-holder.clearfix
.nav-block
@ -10,4 +12,8 @@
- if commit
= render 'shared/commit_well', commit: commit, ref: ref, project: project
- if is_project_overview
.project-buttons.append-bottom-default
= render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
= render 'projects/tree/tree_content', tree: @tree, content_url: content_url

View File

@ -1,83 +1,75 @@
- empty_repo = @project.empty_repo?
- license = @project.license_anchor_data
- show_auto_devops_callout = show_auto_devops_callout?(@project)
.project-home-panel{ class: ("empty-project" if empty_repo) }
.limit-container-width{ class: container_class }
.project-header.d-flex.flex-row.flex-wrap.align-items-center.append-bottom-8
.project-title-row.d-flex.align-items-center
.avatar-container.project-avatar.float-none
= project_icon(@project, alt: @project.name, class: 'avatar avatar-tile s24', width: 24, height: 24)
%h1.project-title.d-flex.align-items-baseline.qa-project-name
= @project.name
.project-metadata.d-flex.flex-row.flex-wrap.align-items-baseline
.project-visibility.d-inline-flex.align-items-baseline.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@project) }
= visibility_level_icon(@project.visibility_level, fw: false, options: {class: 'icon'})
= visibility_level_label(@project.visibility_level)
- if license.present?
.project-license.d-inline-flex.align-items-baseline
= link_to_if license.link, sprite_icon('scale', size: 16, css_class: 'icon') + license.label, license.link, class: license.enabled ? 'btn btn-link btn-secondary-hover-link' : 'btn btn-link'
- if @project.tag_list.present?
.project-tag-list.d-inline-flex.align-items-baseline.has-tooltip{ data: { container: 'body' }, title: @project.has_extra_tags? ? @project.tag_list.join(', ') : nil }
= sprite_icon('tag', size: 16, css_class: 'icon')
= @project.tags_to_show
- if @project.has_extra_tags?
= _("+ %{count} more") % { count: @project.count_of_extra_tags_not_shown }
.project-header.row.append-bottom-8
.project-title-row.col-md-12.col-lg-7.d-flex
.avatar-container.project-avatar.float-none
= project_icon(@project, alt: @project.name, class: 'avatar avatar-tile s64', width: 64, height: 64)
.d-flex.flex-column.flex-wrap.align-items-baseline
.d-inline-flex.align-items-baseline
%h1.project-title.qa-project-name
= @project.name
%span.project-visibility.prepend-left-8.d-inline-flex.align-items-baseline.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@project) }
= visibility_level_icon(@project.visibility_level, fw: false, options: {class: 'icon'})
.project-metadata.d-flex.align-items-center
- if can?(current_user, :read_project, @project)
%span.text-secondary
= s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
- if current_user
%span.access-request-links.prepend-left-8
= render 'shared/members/access_request_links', source: @project
- if @project.tag_list.present?
%span.project-tag-list.d-inline-flex.prepend-left-8.has-tooltip{ data: { container: 'body' }, title: @project.has_extra_tags? ? @project.tag_list.join(', ') : nil }
= sprite_icon('tag', size: 16, css_class: 'icon append-right-4')
= @project.tags_to_show
- if @project.has_extra_tags?
= _("+ %{count} more") % { count: @project.count_of_extra_tags_not_shown }
.project-home-desc
- if @project.description.present?
.project-description
.project-description-markdown.read-more-container
= markdown_field(@project, :description)
%button.btn.btn-blank.btn-link.text-secondary.js-read-more-trigger.text-secondary.d-lg-none{ type: "button" }
= _("Read more")
.project-repo-buttons.col-md-12.col-lg-5.d-inline-flex.flex-wrap.justify-content-lg-end
- if current_user
.d-inline-flex
= render 'projects/buttons/notifications', notification_setting: @notification_setting, btn_class: 'btn-xs'
- if can?(current_user, :read_project, @project)
.text-secondary.prepend-top-8
= s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
- if @project.forked?
%p
- if @project.fork_source
#{ s_('ForkedFromProjectPath|Forked from') }
= link_to project_path(@project.fork_source) do
= fork_source_name(@project)
- else
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_source_name(@project) }
- if @project.badges.present?
.project-badges.prepend-top-default.append-bottom-default
- @project.badges.each do |badge|
%a.append-right-8{ href: badge.rendered_link_url(@project),
target: '_blank',
rel: 'noopener noreferrer' }>
%img.project-badge{ src: badge.rendered_image_url(@project),
'aria-hidden': true,
alt: 'Project badge' }>
.project-repo-buttons.d-inline-flex.flex-wrap
.count-buttons.d-inline-flex
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
- if can?(current_user, :download_code, @project)
.project-clone-holder.d-inline-flex.d-sm-none
.project-clone-holder.d-inline-flex.d-md-none.btn-block
= render "shared/mobile_clone_panel"
.project-clone-holder.d-none.d-sm-inline-flex
= render "shared/clone_panel"
.project-clone-holder.d-none.d-md-inline-flex
= render "projects/buttons/clone"
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline
= render "projects/buttons/xcode_link"
- if can?(current_user, :download_code, @project)
%nav.project-stats
.nav-links.quick-links.mt-3
= render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout)
- if current_user
- if can?(current_user, :download_code, @project)
.d-none.d-sm-inline-flex
= render 'projects/buttons/download', project: @project, ref: @ref
.d-none.d-sm-inline-flex
= render 'projects/buttons/dropdown'
.project-home-desc.mt-1
- if @project.description.present?
.project-description
.project-description-markdown.read-more-container
= markdown_field(@project, :description)
%button.btn.btn-blank.btn-link.js-read-more-trigger.d-lg-none{ type: "button" }
= _("Read more")
.d-none.d-sm-inline-flex
= render 'shared/notifications/button', notification_setting: @notification_setting
.d-none.d-sm-inline-flex
= render 'shared/members/access_request_buttons', source: @project
- if @project.forked?
%p
- if @project.fork_source
#{ s_('ForkedFromProjectPath|Forked from') }
= link_to project_path(@project.fork_source) do
= fork_source_name(@project)
- else
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_source_name(@project) }
- if @project.badges.present?
.project-badges.mb-2
- @project.badges.each do |badge|
%a.append-right-8{ href: badge.rendered_link_url(@project),
target: '_blank',
rel: 'noopener noreferrer' }>
%img.project-badge{ src: badge.rendered_image_url(@project),
'aria-hidden': true,
alt: 'Project badge' }>

View File

@ -4,5 +4,5 @@
%ul.nav
- anchors.each do |anchor|
%li.nav-item
= link_to_if anchor.link, anchor.label, anchor.link, class: anchor.enabled ? 'nav-link stat-link' : "nav-link btn btn-#{anchor.class_modifier || 'missing'}" do
.stat-text= anchor.label
= link_to_if anchor.link, anchor.label, anchor.link, class: anchor.is_link ? 'nav-link stat-link d-flex align-items-center' : "nav-link btn btn-#{anchor.class_modifier || 'missing'} d-flex align-items-center" do
.stat-text.d-flex.align-items-center= anchor.label

View File

@ -0,0 +1,31 @@
- project = project || @project
.git-clone-holder.js-git-clone-holder.input-group
- if allowed_protocols_present?
.input-group-text.clone-dropdown-btn.btn
%span.js-clone-dropdown-label
= enabled_project_button(project, enabled_protocol)
- else
%a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
%span.append-right-4.js-clone-dropdown-label
= _('Clone')
= sprite_icon("arrow-down", css_class: "icon")
%form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown
%li.pb-2
%label.label-bold
= _('Clone with SSH')
.input-group
= text_field_tag :ssh_project_clone, project.ssh_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' }
.input-group-append
= clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard")
= render_if_exists 'projects/buttons/geo'
%li
%label.label-bold
= _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase }
.input-group
= text_field_tag :http_project_clone, project.http_url_to_repo, class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' }
.input-group-append
= clipboard_button(target: '#http_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard")
= render_if_exists 'projects/buttons/geo'
= render_if_exists 'shared/geo_info_modal', project: project

View File

@ -5,8 +5,8 @@
.project-action-button.dropdown.inline>
%button.btn.has-tooltip{ title: s_('DownloadSource|Download'), 'data-toggle' => 'dropdown', 'aria-label' => s_('DownloadSource|Download'), 'data-display' => 'static' }
= sprite_icon('download')
= icon("caret-down")
%span.sr-only= _('Select Archive Format')
= sprite_icon("arrow-down")
%ul.dropdown-menu.dropdown-menu-right{ role: 'menu' }
%li.dropdown-header
#{ _('Source code') }

View File

@ -1,9 +1,6 @@
- unless @project.empty_repo?
- if current_user && can?(current_user, :fork_project, @project)
.count-badge.d-inline-flex.align-item-stretch.append-right-8
%span.fork-count.count-badge-count.d-flex.align-items-center
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Fork'), s_('ProjectOverview|Forks'), @project.forks_count), class: 'count' do
= @project.forks_count
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'btn btn-default has-tooltip count-badge-button d-flex align-items-center fork-btn' do
= sprite_icon('fork', { css_class: 'icon' })
@ -15,3 +12,6 @@
title: (s_('ProjectOverview|You have reached your project limit') unless can_create_fork) do
= sprite_icon('fork', { css_class: 'icon' })
%span= s_('ProjectOverview|Fork')
%span.fork-count.count-badge-count.d-flex.align-items-center
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Fork'), s_('ProjectOverview|Forks'), @project.forks_count), class: 'count' do
= @project.forks_count

View File

@ -0,0 +1,27 @@
- btn_class = local_assigns.fetch(:btn_class, "btn-xs")
- if notification_setting
.js-notification-dropdown.notification-dropdown.project-action-button.dropdown.inline
= form_for notification_setting, remote: true, html: { class: "inline notification-form no-label" } do |f|
= hidden_setting_source_input(notification_setting)
= hidden_field_tag "hide_label", true
= f.hidden_field :level, class: "notification_setting_level"
.js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom?
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }, class: "#{btn_class}", "aria-label" => _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= sprite_icon("notifications", css_class: "icon notifications-icon js-notifications-icon")
%span.js-notification-loading.fa.hidden
%button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= sprite_icon("arrow-down", css_class: "icon")
.sr-only Toggle dropdown
- else
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting - #{notification_title(notification_setting.level)}", class: "#{btn_class}", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= sprite_icon("notifications", css_class: "icon notifications-icon js-notifications-icon")
%span.js-notification-loading.fa.hidden
= sprite_icon("arrow-down", css_class: "icon")
= render "shared/notifications/notification_dropdown", notification_setting: notification_setting
= content_for :scripts_body do
= render "shared/notifications/custom_notifications", notification_setting: notification_setting

View File

@ -1,19 +1,19 @@
- if current_user
.count-badge.d-inline-flex.align-item-stretch.append-right-8
%span.star-count.count-badge-count.d-flex.align-items-center
= @project.star_count
%button.count-badge-button.btn.btn-default.d-flex.align-items-center.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } }
%button.count-badge-button.btn.btn-default.btn-xs.d-flex.align-items-center.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } }
- if current_user.starred?(@project)
= sprite_icon('star', { css_class: 'icon' })
%span.starred= s_('ProjectOverview|Unstar')
- else
= sprite_icon('star-o', { css_class: 'icon' })
%span= s_('ProjectOverview|Star')
%span.star-count.count-badge-count.d-flex.align-items-center
= @project.star_count
- else
.count-badge.d-inline-flex.align-item-stretch.append-right-8
%span.star-count.count-badge-count.d-flex.align-items-center
= @project.star_count
= link_to new_user_session_path, class: 'btn btn-default has-tooltip count-badge-button d-flex align-items-center star-btn', title: s_('ProjectOverview|You must sign in to star a project') do
= link_to new_user_session_path, class: 'btn btn-default btn-xs has-tooltip count-badge-button d-flex align-items-center star-btn', title: s_('ProjectOverview|You must sign in to star a project') do
= sprite_icon('star-o', { css_class: 'icon' })
%span= s_('ProjectOverview|Star')
%span.star-count.count-badge-count.d-flex.align-items-center
= @project.star_count

View File

@ -4,11 +4,10 @@
= render partial: 'flash_messages', locals: { project: @project }
= render "home_panel"
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render "home_panel"
.project-empty-note-panel
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.prepend-top-20
.project-empty-note-panel
%h4.append-bottom-20
= _('The repository for this project is empty')
@ -32,66 +31,65 @@
= _('Otherwise it is recommended you start with one of the options below.')
.prepend-top-20
%nav.project-stats{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.quick-links
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_anchors
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
%nav.project-buttons
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.quick-links
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- if can?(current_user, :push_code, @project)
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.prepend-top-20
.empty_wrapper
%h3#repo-command-line-instructions.page-title-empty
Command line instructions
.git-empty.js-git-empty
%fieldset
%h5 Git global setup
%pre.bg-light
:preserve
git config --global user.name "#{h git_user_name}"
git config --global user.email "#{h git_user_email}"
- if can?(current_user, :push_code, @project)
%div
.prepend-top-20
.empty_wrapper
%h3#repo-command-line-instructions.page-title-empty
= _('Command line instructions')
.git-empty.js-git-empty
%fieldset
%h5= _('Git global setup')
%pre.bg-light
:preserve
git config --global user.name "#{h git_user_name}"
git config --global user.email "#{h git_user_email}"
%fieldset
%h5 Create a new repository
%pre.bg-light
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
cd #{h @project.path}
touch README.md
git add README.md
git commit -m "add README"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5= _('Create a new repository')
%pre.bg-light
:preserve
git clone #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
cd #{h @project.path}
touch README.md
git add README.md
git commit -m "add README"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5 Existing folder
%pre.bg-light
:preserve
cd existing_folder
git init
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
git add .
git commit -m "Initial commit"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5= _('Existing folder')
%pre.bg-light
:preserve
cd existing_folder
git init
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
git add .
git commit -m "Initial commit"
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin master
%fieldset
%h5 Existing Git repository
%pre.bg-light
:preserve
cd existing_repo
git remote rename origin old-origin
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin --all
git push -u origin --tags
%fieldset
%h5= _('Existing Git repository')
%pre.bg-light
:preserve
cd existing_repo
git remote rename origin old-origin
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'js-clone')}
- if @project.can_current_user_push_to_default_branch?
%span><
git push -u origin --all
git push -u origin --tags
- if can? current_user, :remove_project, @project
.prepend-top-20
= link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove float-right"
- if can? current_user, :remove_project, @project
.prepend-top-20
= link_to _('Remove project'), [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove float-right"

View File

@ -1,7 +1,6 @@
- @no_container = true
- breadcrumb_title _("Details")
- @content_class = "limit-container-width" unless fluid_layout
- show_auto_devops_callout = show_auto_devops_callout?(@project)
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity")
@ -15,20 +14,11 @@
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render "projects/last_push"
= render "home_panel"
- if can?(current_user, :download_code, @project)
%nav.project-stats{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.quick-links
= render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout)
= render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
= render "home_panel"
- if can?(current_user, :download_code, @project) && @project.repository_languages.present?
= repository_languages_bar(@project.repository_languages)
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
- if @project.archived?
.text-warning.center.prepend-top-20
%p
@ -41,4 +31,4 @@
= render 'shared/auto_devops_callout'
%div{ class: project_child_container_class(view_path) }
= render view_path
= render view_path, is_project_overview: true

View File

@ -85,4 +85,8 @@
= link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do
= _('Web IDE')
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline
= render "projects/buttons/xcode_link"
= render 'projects/buttons/download', project: @project, ref: @ref

View File

@ -1,13 +1,13 @@
- project = project || @project
- ssh_copy_label = _("Copy SSH clone URL")
- http_copy_label = _("Copy HTTPS clone URL")
- http_copy_label = _('Copy %{http_label} clone URL') % { http_label: gitlab_config.protocol.upcase }
.btn-group.mobile-git-clone.js-mobile-git-clone
= clipboard_button(button_text: default_clone_label, target: '#project_clone', hide_button_icon: true, class: "input-group-text clone-dropdown-btn js-clone-dropdown-label btn btn-default")
%button.btn.btn-default.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { toggle: "dropdown" } }
= icon("caret-down", class: "dropdown-btn-icon")
.btn-group.mobile-git-clone.js-mobile-git-clone.btn-block
= clipboard_button(button_text: default_clone_label, text: default_url_to_repo(project), hide_button_icon: true, class: "btn-primary flex-fill bold justify-content-center input-group-text clone-dropdown-btn js-clone-dropdown-label")
%button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { toggle: "dropdown" } }
= sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon")
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
%li
= dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' })
= dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true)
%li
= dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' })

View File

@ -0,0 +1,17 @@
- model_name = source.model_name.to_s.downcase
- if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id)) # rubocop: disable CodeReuse/ActiveRecord
- link_text = source.is_a?(Group) ? _('Leave group') : _('Leave project')
= link_to link_text, polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: leave_confirmation_message(source) },
class: 'access-request-link'
- elsif requester = source.requesters.find_by(user_id: current_user.id) # rubocop: disable CodeReuse/ActiveRecord
= link_to _('Withdraw Access Request'), polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: remove_member_message(requester) },
class: 'access-request-link'
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to _('Request Access'), polymorphic_path([:request_access, source, :members]),
method: :post,
class: 'access-request-link'

View File

@ -1,3 +1,5 @@
- btn_class = local_assigns.fetch(:btn_class, nil)
- if notification_setting
.js-notification-dropdown.notification-dropdown.project-action-button.dropdown.inline
= form_for notification_setting, remote: true, html: { class: "inline notification-form" } do |f|
@ -6,14 +8,14 @@
.js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom?
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: _("Notification setting"), class: "#{btn_class}", "aria-label" => _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
%button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= icon('caret-down')
.sr-only Toggle dropdown
- else
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", class: "#{btn_class}", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
= icon("caret-down")

View File

@ -0,0 +1,5 @@
---
title: Design improvements to project overview page
merge_request: 22196
author:
type: changed

View File

@ -141,6 +141,24 @@ msgstr ""
msgid "%{percent}%% complete"
msgstr ""
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
msgstr[1] ""
msgid "%{strong_start}%{commit_count}%{strong_end} Commit"
msgid_plural "%{strong_start}%{commit_count}%{strong_end} Commits"
msgstr[0] ""
msgstr[1] ""
msgid "%{strong_start}%{human_size}%{strong_end} Files"
msgstr ""
msgid "%{strong_start}%{tag_count}%{strong_end} Tag"
msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
msgstr[0] ""
msgstr[1] ""
msgid "%{text} %{files}"
msgid_plural "%{text} %{files} files"
msgstr[0] ""
@ -333,16 +351,16 @@ msgstr ""
msgid "Activity"
msgstr ""
msgid "Add Changelog"
msgid "Add CHANGELOG"
msgstr ""
msgid "Add Contribution guide"
msgid "Add CONTRIBUTING"
msgstr ""
msgid "Add Kubernetes cluster"
msgstr ""
msgid "Add Readme"
msgid "Add README"
msgstr ""
msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
@ -945,11 +963,6 @@ msgstr ""
msgid "Branch %{branchName} was not found in this project's repository."
msgstr ""
msgid "Branch (%{branch_count})"
msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
@ -1103,6 +1116,9 @@ msgstr ""
msgid "ByAuthor|by"
msgstr ""
msgid "CHANGELOG"
msgstr ""
msgid "CI / CD"
msgstr ""
@ -1160,6 +1176,9 @@ msgstr ""
msgid "CICD|instance enabled"
msgstr ""
msgid "CONTRIBUTING"
msgstr ""
msgid "Callback URL"
msgstr ""
@ -1202,9 +1221,6 @@ msgstr ""
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
msgstr ""
msgid "Changelog"
msgstr ""
msgid "Changes are shown as if the <b>source</b> revision was being merged into the <b>target</b> revision."
msgstr ""
@ -1388,9 +1404,18 @@ msgstr ""
msgid "Clients"
msgstr ""
msgid "Clone"
msgstr ""
msgid "Clone repository"
msgstr ""
msgid "Clone with %{http_label}"
msgstr ""
msgid "Clone with SSH"
msgstr ""
msgid "Close"
msgstr ""
@ -1811,6 +1836,9 @@ msgstr ""
msgid "Collapse sidebar"
msgstr ""
msgid "Command line instructions"
msgstr ""
msgid "Comment"
msgstr ""
@ -1831,11 +1859,6 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgid "Commit (%{commit_count})"
msgid_plural "Commits (%{commit_count})"
msgstr[0] ""
msgstr[1] ""
msgid "Commit Message"
msgstr ""
@ -2019,9 +2042,6 @@ msgstr ""
msgid "Contribution Charts"
msgstr ""
msgid "Contribution guide"
msgstr ""
msgid "Contributions for <strong>%{calendar_date}</strong>"
msgstr ""
@ -2046,10 +2066,10 @@ msgstr ""
msgid "ConvDev Index"
msgstr ""
msgid "Copy %{protocol} clone URL"
msgid "Copy %{http_label} clone URL"
msgstr ""
msgid "Copy HTTPS clone URL"
msgid "Copy %{protocol} clone URL"
msgstr ""
msgid "Copy ID to clipboard"
@ -2112,6 +2132,9 @@ msgstr ""
msgid "Create a new issue"
msgstr ""
msgid "Create a new repository"
msgstr ""
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
@ -2870,6 +2893,12 @@ msgstr ""
msgid "Everyone can contribute"
msgstr ""
msgid "Existing Git repository"
msgstr ""
msgid "Existing folder"
msgstr ""
msgid "Expand"
msgstr ""
@ -2978,9 +3007,6 @@ msgstr ""
msgid "Files"
msgstr ""
msgid "Files (%{human_size})"
msgstr ""
msgid "Filter"
msgstr ""
@ -3107,6 +3133,9 @@ msgstr ""
msgid "Git"
msgstr ""
msgid "Git global setup"
msgstr ""
msgid "Git repository URL"
msgstr ""
@ -4438,6 +4467,12 @@ msgstr ""
msgid "Notification events"
msgstr ""
msgid "Notification setting"
msgstr ""
msgid "Notification setting - %{notification_title}"
msgstr ""
msgid "NotificationEvent|Close issue"
msgstr ""
@ -5349,6 +5384,9 @@ msgstr ""
msgid "Quick actions can be used in the issues description and comment boxes."
msgstr ""
msgid "README"
msgstr ""
msgid "Read more"
msgstr ""
@ -5358,9 +5396,6 @@ msgstr ""
msgid "Read more about project permissions <strong>%{link_to_help}</strong>"
msgstr ""
msgid "Readme"
msgstr ""
msgid "Real-time features"
msgstr ""
@ -6294,11 +6329,6 @@ msgstr ""
msgid "System metrics (Kubernetes)"
msgstr ""
msgid "Tag (%{tag_count})"
msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
msgid "Tags"
msgstr ""

View File

@ -10,54 +10,9 @@ describe 'Projects > Show > Developer views empty project instructions' do
sign_in(developer)
end
context 'without an SSH key' do
it 'defaults to HTTP' do
visit_project
expect_instructions_for('http')
end
it 'switches to SSH', :js do
visit_project
select_protocol('SSH')
expect_instructions_for('ssh')
end
end
context 'with an SSH key' do
before do
create(:personal_key, user: developer)
end
it 'defaults to SSH' do
visit_project
expect_instructions_for('ssh')
end
it 'switches to HTTP', :js do
visit_project
select_protocol('HTTP')
expect_instructions_for('http')
end
end
def visit_project
it 'displays "git clone" instructions' do
visit project_path(project)
end
def select_protocol(protocol)
find('#clone-dropdown').click
find(".#{protocol.downcase}-selector").click
end
def expect_instructions_for(protocol)
msg = :"#{protocol.downcase}_url_to_repo"
expect(page).to have_content("git clone #{project.send(msg)}")
expect(page).to have_content("git clone")
end
end

View File

@ -8,13 +8,18 @@ describe 'Projects > Show > User manages notifications', :js do
visit project_path(project)
end
it 'changes the notification setting' do
def click_notifications_button
first('.notifications-btn').click
end
it 'changes the notification setting' do
click_notifications_button
click_link 'On mention'
page.within '#notifications-button' do
expect(page).to have_content 'On mention'
end
wait_for_requests
click_notifications_button
expect(find('.update-notification.is-active')).to have_content('On mention')
end
context 'custom notification settings' do
@ -38,7 +43,7 @@ describe 'Projects > Show > User manages notifications', :js do
end
it 'shows notification settings checkbox' do
first('.notifications-btn').click
click_notifications_button
page.find('a[data-notification-level="custom"]').click
page.within('.custom-notifications-form') do

View File

@ -21,18 +21,6 @@ describe 'Projects > Show > Collaboration links' do
end
end
# The project header
page.within('.project-home-panel') do
aggregate_failures 'dropdown links in the project home panel' do
expect(page).to have_link('New issue')
expect(page).to have_link('New merge request')
expect(page).to have_link('New snippet')
expect(page).to have_link('New file')
expect(page).to have_link('New branch')
expect(page).to have_link('New tag')
end
end
# The dropdown above the tree
page.within('.repo-breadcrumb') do
aggregate_failures 'dropdown links above the repo tree' do
@ -61,17 +49,6 @@ describe 'Projects > Show > Collaboration links' do
end
end
page.within('.project-home-panel') do
aggregate_failures 'dropdown links' do
expect(page).not_to have_link('New issue')
expect(page).not_to have_link('New merge request')
expect(page).not_to have_link('New snippet')
expect(page).not_to have_link('New file')
expect(page).not_to have_link('New branch')
expect(page).not_to have_link('New tag')
end
end
page.within('.repo-breadcrumb') do
aggregate_failures 'dropdown links' do
expect(page).not_to have_link('New file')

View File

@ -29,7 +29,7 @@ describe 'Projects > Show > User sees Git instructions' do
expect(element.text).to include(project.http_url_to_repo)
end
expect(page).to have_field('project_clone', with: project.http_url_to_repo) unless user_has_ssh_key
expect(page).to have_field('http_project_clone', with: project.http_url_to_repo) unless user_has_ssh_key
end
end
@ -41,7 +41,7 @@ describe 'Projects > Show > User sees Git instructions' do
expect(page).to have_content(project.title)
end
expect(page).to have_field('project_clone', with: project.http_url_to_repo) unless user_has_ssh_key
expect(page).to have_field('http_project_clone', with: project.http_url_to_repo) unless user_has_ssh_key
end
end

View File

@ -21,7 +21,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
end
it 'no Auto DevOps button if can not manage pipelines' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Enable Auto DevOps')
expect(page).not_to have_link('Auto DevOps enabled')
end
@ -30,7 +30,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Auto DevOps enabled" button not linked' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_text('Auto DevOps enabled')
end
end
@ -45,19 +45,19 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
end
it '"New file" button linked to new file page' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('New file', href: project_new_blob_path(project, project.default_branch || 'master'))
end
end
it '"Add Readme" button linked to new file populated for a readme' do
page.within('.project-stats') do
expect(page).to have_link('Add Readme', href: presenter.add_readme_path)
it '"Add README" button linked to new file populated for a README' do
page.within('.project-buttons') do
expect(page).to have_link('Add README', href: presenter.add_readme_path)
end
end
it '"Add license" button linked to new file populated for a license' do
page.within('.project-metadata') do
page.within('.project-stats') do
expect(page).to have_link('Add license', href: presenter.add_license_path)
end
end
@ -67,7 +67,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Auto DevOps enabled" anchor linked to settings page' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
end
@ -77,7 +77,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
let(:project) { create(:project, :public, :empty_repo, auto_devops_attributes: { enabled: false }) }
it '"Enable Auto DevOps" button linked to settings page' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
end
@ -86,7 +86,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
describe 'Kubernetes cluster button' do
it '"Add Kubernetes cluster" button linked to clusters page' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Add Kubernetes cluster', href: new_project_cluster_path(project))
end
end
@ -96,7 +96,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Kubernetes configured', href: project_cluster_path(project, cluster))
end
end
@ -119,7 +119,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Auto DevOps enabled" button not linked' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_text('Auto DevOps enabled')
end
end
@ -129,14 +129,14 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
let(:project) { create(:project, :public, :repository, auto_devops_attributes: { enabled: false }) }
it 'no Auto DevOps button if can not manage pipelines' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Enable Auto DevOps')
expect(page).not_to have_link('Auto DevOps enabled')
end
end
it 'no Kubernetes cluster button if can not manage clusters' do
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Add Kubernetes cluster')
expect(page).not_to have_link('Kubernetes configured')
end
@ -151,59 +151,59 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
sign_in(user)
end
context 'Readme button' do
context 'README button' do
before do
allow(Project).to receive(:find_by_full_path)
.with(project.full_path, follow_redirects: true)
.and_return(project)
end
context 'when the project has a populated Readme' do
it 'show the "Readme" anchor' do
context 'when the project has a populated README' do
it 'show the "README" anchor' do
visit project_path(project)
expect(project.repository.readme).not_to be_nil
page.within('.project-stats') do
expect(page).not_to have_link('Add Readme', href: presenter.add_readme_path)
expect(page).to have_link('Readme', href: presenter.readme_path)
page.within('.project-buttons') do
expect(page).not_to have_link('Add README', href: presenter.add_readme_path)
expect(page).to have_link('README', href: presenter.readme_path)
end
end
context 'when the project has an empty Readme' do
it 'show the "Readme" anchor' do
context 'when the project has an empty README' do
it 'show the "README" anchor' do
allow(project.repository).to receive(:readme).and_return(fake_blob(path: 'README.md', data: '', size: 0))
visit project_path(project)
page.within('.project-stats') do
expect(page).not_to have_link('Add Readme', href: presenter.add_readme_path)
expect(page).to have_link('Readme', href: presenter.readme_path)
page.within('.project-buttons') do
expect(page).not_to have_link('Add README', href: presenter.add_readme_path)
expect(page).to have_link('README', href: presenter.readme_path)
end
end
end
end
context 'when the project does not have a Readme' do
it 'shows the "Add Readme" button' do
context 'when the project does not have a README' do
it 'shows the "Add README" button' do
allow(project.repository).to receive(:readme).and_return(nil)
visit project_path(project)
page.within('.project-stats') do
expect(page).to have_link('Add Readme', href: presenter.add_readme_path)
page.within('.project-buttons') do
expect(page).to have_link('Add README', href: presenter.add_readme_path)
end
end
end
end
it 'no "Add Changelog" button if the project already has a changelog' do
it 'no "Add CHANGELOG" button if the project already has a changelog' do
visit project_path(project)
expect(project.repository.changelog).not_to be_nil
page.within('.project-stats') do
expect(page).not_to have_link('Add Changelog')
page.within('.project-buttons') do
expect(page).not_to have_link('Add CHANGELOG')
end
end
@ -212,18 +212,18 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
expect(project.repository.license_blob).not_to be_nil
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Add license')
end
end
it 'no "Add Contribution guide" button if the project already has a contribution guide' do
it 'no "Add CONTRIBUTING" button if the project already has a contribution guide' do
visit project_path(project)
expect(project.repository.contribution_guide).not_to be_nil
page.within('.project-stats') do
expect(page).not_to have_link('Add Contribution guide')
page.within('.project-buttons') do
expect(page).not_to have_link('Add CONTRIBUTING')
end
end
@ -232,7 +232,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it 'no "Set up CI/CD" button if the project has Auto DevOps enabled' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Set up CI/CD')
end
end
@ -246,7 +246,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
expect(project.repository.gitlab_ci_yml).to be_nil
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
end
end
@ -266,7 +266,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Set up CI/CD')
end
end
@ -278,7 +278,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Auto DevOps enabled" anchor linked to settings page' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
end
@ -290,7 +290,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Enable Auto DevOps" button linked to settings page' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
end
@ -302,7 +302,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
expect(page).to have_selector('.js-autodevops-banner')
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Enable Auto DevOps')
expect(page).not_to have_link('Auto DevOps enabled')
end
@ -323,7 +323,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).not_to have_link('Enable Auto DevOps')
expect(page).not_to have_link('Auto DevOps enabled')
end
@ -335,7 +335,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
it '"Add Kubernetes cluster" button linked to clusters page' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Add Kubernetes cluster', href: new_project_cluster_path(project))
end
end
@ -345,7 +345,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
page.within('.project-stats') do
page.within('.project-buttons') do
expect(page).to have_link('Kubernetes configured', href: project_cluster_path(project, cluster))
end
end

View File

@ -13,7 +13,7 @@ describe 'Maintainer views tags' do
before do
visit project_path(project)
click_on 'Add Readme'
click_on 'Add README'
fill_in :commit_message, with: 'Add a README file', visible: true
click_button 'Commit changes'
visit project_tags_path(project)

View File

@ -165,32 +165,32 @@ describe ProjectPresenter do
describe '#files_anchor_data' do
it 'returns files data' do
expect(presenter.files_anchor_data).to have_attributes(enabled: true,
label: 'Files (0 Bytes)',
expect(presenter.files_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0 Bytes'),
link: nil)
end
end
describe '#commits_anchor_data' do
it 'returns commits data' do
expect(presenter.commits_anchor_data).to have_attributes(enabled: true,
label: 'Commits (0)',
expect(presenter.commits_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0'),
link: nil)
end
end
describe '#branches_anchor_data' do
it 'returns branches data' do
expect(presenter.branches_anchor_data).to have_attributes(enabled: true,
label: "Branches (0)",
expect(presenter.branches_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0'),
link: nil)
end
end
describe '#tags_anchor_data' do
it 'returns tags data' do
expect(presenter.tags_anchor_data).to have_attributes(enabled: true,
label: "Tags (0)",
expect(presenter.tags_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0'),
link: nil)
end
end
@ -202,32 +202,32 @@ describe ProjectPresenter do
describe '#files_anchor_data' do
it 'returns files data' do
expect(presenter.files_anchor_data).to have_attributes(enabled: true,
label: 'Files (0 Bytes)',
expect(presenter.files_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0 Bytes'),
link: presenter.project_tree_path(project))
end
end
describe '#commits_anchor_data' do
it 'returns commits data' do
expect(presenter.commits_anchor_data).to have_attributes(enabled: true,
label: 'Commits (0)',
expect(presenter.commits_anchor_data).to have_attributes(is_link: true,
label: a_string_including('0'),
link: presenter.project_commits_path(project, project.repository.root_ref))
end
end
describe '#branches_anchor_data' do
it 'returns branches data' do
expect(presenter.branches_anchor_data).to have_attributes(enabled: true,
label: "Branches (#{project.repository.branches.size})",
expect(presenter.branches_anchor_data).to have_attributes(is_link: true,
label: a_string_including("#{project.repository.branches.size}"),
link: presenter.project_branches_path(project))
end
end
describe '#tags_anchor_data' do
it 'returns tags data' do
expect(presenter.tags_anchor_data).to have_attributes(enabled: true,
label: "Tags (#{project.repository.tags.size})",
expect(presenter.tags_anchor_data).to have_attributes(is_link: true,
label: a_string_including("#{project.repository.tags.size}"),
link: presenter.project_tags_path(project))
end
end
@ -236,8 +236,8 @@ describe ProjectPresenter do
it 'returns new file data if user can push' do
project.add_developer(user)
expect(presenter.new_file_anchor_data).to have_attributes(enabled: false,
label: "New file",
expect(presenter.new_file_anchor_data).to have_attributes(is_link: false,
label: a_string_including("New file"),
link: presenter.project_new_blob_path(project, 'master'),
class_modifier: 'success')
end
@ -264,8 +264,8 @@ describe ProjectPresenter do
project.add_developer(user)
allow(project.repository).to receive(:readme).and_return(nil)
expect(presenter.readme_anchor_data).to have_attributes(enabled: false,
label: 'Add Readme',
expect(presenter.readme_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Add README'),
link: presenter.add_readme_path)
end
end
@ -274,21 +274,21 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:readme).and_return(double(name: 'readme'))
expect(presenter.readme_anchor_data).to have_attributes(enabled: true,
label: 'Readme',
expect(presenter.readme_anchor_data).to have_attributes(is_link: false,
label: a_string_including('README'),
link: presenter.readme_path)
end
end
end
describe '#changelog_anchor_data' do
context 'when user can push and CHANGELOG does not exists' do
context 'when user can push and CHANGELOG does not exist' do
it 'returns anchor data' do
project.add_developer(user)
allow(project.repository).to receive(:changelog).and_return(nil)
expect(presenter.changelog_anchor_data).to have_attributes(enabled: false,
label: 'Add Changelog',
expect(presenter.changelog_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Add CHANGELOG'),
link: presenter.add_changelog_path)
end
end
@ -297,21 +297,21 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:changelog).and_return(double(name: 'foo'))
expect(presenter.changelog_anchor_data).to have_attributes(enabled: true,
label: 'Changelog',
expect(presenter.changelog_anchor_data).to have_attributes(is_link: false,
label: a_string_including('CHANGELOG'),
link: presenter.changelog_path)
end
end
end
describe '#license_anchor_data' do
context 'when user can push and LICENSE does not exists' do
context 'when user can push and LICENSE does not exist' do
it 'returns anchor data' do
project.add_developer(user)
allow(project.repository).to receive(:license_blob).and_return(nil)
expect(presenter.license_anchor_data).to have_attributes(enabled: false,
label: 'Add license',
expect(presenter.license_anchor_data).to have_attributes(is_link: true,
label: a_string_including('Add license'),
link: presenter.add_license_path)
end
end
@ -320,21 +320,21 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:license_blob).and_return(double(name: 'foo'))
expect(presenter.license_anchor_data).to have_attributes(enabled: true,
label: presenter.license_short_name,
expect(presenter.license_anchor_data).to have_attributes(is_link: true,
label: a_string_including(presenter.license_short_name),
link: presenter.license_path)
end
end
end
describe '#contribution_guide_anchor_data' do
context 'when user can push and CONTRIBUTING does not exists' do
context 'when user can push and CONTRIBUTING does not exist' do
it 'returns anchor data' do
project.add_developer(user)
allow(project.repository).to receive(:contribution_guide).and_return(nil)
expect(presenter.contribution_guide_anchor_data).to have_attributes(enabled: false,
label: 'Add Contribution guide',
expect(presenter.contribution_guide_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Add CONTRIBUTING'),
link: presenter.add_contribution_guide_path)
end
end
@ -343,8 +343,8 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:contribution_guide).and_return(double(name: 'foo'))
expect(presenter.contribution_guide_anchor_data).to have_attributes(enabled: true,
label: 'Contribution guide',
expect(presenter.contribution_guide_anchor_data).to have_attributes(is_link: false,
label: a_string_including('CONTRIBUTING'),
link: presenter.contribution_guide_path)
end
end
@ -355,20 +355,20 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project).to receive(:auto_devops_enabled?).and_return(true)
expect(presenter.autodevops_anchor_data).to have_attributes(enabled: true,
label: 'Auto DevOps enabled',
expect(presenter.autodevops_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Auto DevOps enabled'),
link: nil)
end
end
context 'when user can admin pipeline and CI yml does not exists' do
context 'when user can admin pipeline and CI yml does not exist' do
it 'returns anchor data' do
project.add_maintainer(user)
allow(project).to receive(:auto_devops_enabled?).and_return(false)
allow(project.repository).to receive(:gitlab_ci_yml).and_return(nil)
expect(presenter.autodevops_anchor_data).to have_attributes(enabled: false,
label: 'Enable Auto DevOps',
expect(presenter.autodevops_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Enable Auto DevOps'),
link: presenter.project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end
end
@ -380,8 +380,8 @@ describe ProjectPresenter do
project.add_maintainer(user)
cluster = create(:cluster, projects: [project])
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(enabled: true,
label: 'Kubernetes configured',
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Kubernetes configured'),
link: presenter.project_cluster_path(project, cluster))
end
@ -390,16 +390,16 @@ describe ProjectPresenter do
create(:cluster, :production_environment, projects: [project])
create(:cluster, projects: [project])
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(enabled: true,
label: 'Kubernetes configured',
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Kubernetes configured'),
link: presenter.project_clusters_path(project))
end
it 'returns link to create a cluster if no cluster exists' do
project.add_maintainer(user)
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(enabled: false,
label: 'Add Kubernetes cluster',
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
label: a_string_including('Add Kubernetes cluster'),
link: presenter.new_project_cluster_path(project))
end
end

View File

@ -23,7 +23,7 @@ describe 'projects/_home_panel' do
it 'makes it possible to set notification level' do
render
expect(view).to render_template('shared/notifications/_button')
expect(view).to render_template('projects/buttons/_notifications')
expect(rendered).to have_selector('.notification-dropdown')
end
end