summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/breadcrumb.js28
-rw-r--r--app/assets/javascripts/dispatcher.js7
-rw-r--r--app/assets/javascripts/group_name.js67
-rw-r--r--app/assets/javascripts/main.js3
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss1
-rw-r--r--app/assets/stylesheets/new_nav.scss153
-rw-r--r--app/assets/stylesheets/new_sidebar.scss1
-rw-r--r--app/assets/stylesheets/pages/commits.scss6
-rw-r--r--app/assets/stylesheets/pages/notes.scss18
-rw-r--r--app/controllers/admin/logs_controller.rb9
-rw-r--r--app/controllers/concerns/renders_notes.rb9
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/artifacts_controller.rb12
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb6
-rw-r--r--app/controllers/projects/snippets_controller.rb2
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/helpers/blame_helper.rb16
-rw-r--r--app/helpers/breadcrumbs_helper.rb12
-rw-r--r--app/helpers/groups_helper.rb28
-rw-r--r--app/helpers/issuables_helper.rb19
-rw-r--r--app/helpers/notes_helper.rb2
-rw-r--r--app/helpers/page_layout_helper.rb4
-rw-r--r--app/helpers/profiles_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb15
-rw-r--r--app/helpers/wiki_helper.rb11
-rw-r--r--app/models/concerns/issuable.rb7
-rw-r--r--app/models/merge_request.rb6
-rw-r--r--app/models/note.rb35
-rw-r--r--app/models/project_team.rb2
-rw-r--r--app/models/user.rb22
-rw-r--r--app/models/user_synced_attributes_metadata.rb25
-rw-r--r--app/services/users/update_service.rb4
-rw-r--r--app/views/admin/applications/edit.html.haml2
-rw-r--r--app/views/admin/cohorts/index.html.haml1
-rw-r--r--app/views/admin/dashboard/index.html.haml1
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/admin/hooks/edit.html.haml1
-rw-r--r--app/views/admin/jobs/index.html.haml1
-rw-r--r--app/views/admin/labels/edit.html.haml2
-rw-r--r--app/views/admin/projects/show.html.haml2
-rw-r--r--app/views/admin/runners/index.html.haml1
-rw-r--r--app/views/admin/services/edit.html.haml2
-rw-r--r--app/views/admin/users/show.html.haml2
-rw-r--r--app/views/ci/variables/_content.html.haml12
-rw-r--r--app/views/ci/variables/_index.html.haml4
-rw-r--r--app/views/ci/variables/_show.html.haml2
-rw-r--r--app/views/groups/edit.html.haml1
-rw-r--r--app/views/groups/projects.html.haml1
-rw-r--r--app/views/groups/settings/ci_cd/show.html.haml3
-rw-r--r--app/views/groups/show.html.haml2
-rw-r--r--app/views/groups/subgroups.html.haml1
-rw-r--r--app/views/layouts/nav/_breadcrumbs.html.haml24
-rw-r--r--app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml11
-rw-r--r--app/views/profiles/passwords/edit.html.haml1
-rw-r--r--app/views/profiles/personal_access_tokens/index.html.haml1
-rw-r--r--app/views/profiles/show.html.haml18
-rw-r--r--app/views/projects/activity.html.haml2
-rw-r--r--app/views/projects/artifacts/browse.html.haml4
-rw-r--r--app/views/projects/boards/_show.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/commit/show.html.haml2
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/compare/index.html.haml2
-rw-r--r--app/views/projects/compare/show.html.haml3
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml1
-rw-r--r--app/views/projects/edit.html.haml1
-rw-r--r--app/views/projects/empty.html.haml1
-rw-r--r--app/views/projects/environments/show.html.haml2
-rw-r--r--app/views/projects/graphs/charts.html.haml1
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/jobs/index.html.haml2
-rw-r--r--app/views/projects/jobs/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/network/show.html.haml1
-rw-r--r--app/views/projects/notes/_actions.html.haml8
-rw-r--r--app/views/projects/pipeline_schedules/edit.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml4
-rw-r--r--app/views/projects/pipelines/charts.html.haml2
-rw-r--r--app/views/projects/pipelines/show.html.haml2
-rw-r--r--app/views/projects/pipelines_settings/_badge.html.haml62
-rw-r--r--app/views/projects/pipelines_settings/_show.html.haml5
-rw-r--r--app/views/projects/project_members/index.html.haml2
-rw-r--r--app/views/projects/releases/edit.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml56
-rw-r--r--app/views/projects/settings/integrations/show.html.haml2
-rw-r--r--app/views/projects/settings/repository/show.html.haml2
-rw-r--r--app/views/projects/show.html.haml2
-rw-r--r--app/views/projects/snippets/edit.html.haml2
-rw-r--r--app/views/projects/snippets/new.html.haml2
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/projects/tags/show.html.haml2
-rw-r--r--app/views/projects/triggers/_content.html.haml10
-rw-r--r--app/views/projects/triggers/_index.html.haml3
-rw-r--r--app/views/projects/wikis/pages.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml7
-rw-r--r--app/views/shared/snippets/_header.html.haml4
-rw-r--r--app/views/snippets/show.html.haml2
102 files changed, 511 insertions, 365 deletions
diff --git a/app/assets/javascripts/breadcrumb.js b/app/assets/javascripts/breadcrumb.js
new file mode 100644
index 00000000000..10fbcfe96cf
--- /dev/null
+++ b/app/assets/javascripts/breadcrumb.js
@@ -0,0 +1,28 @@
+export const addTooltipToEl = (el) => {
+ const textEl = el.querySelector('.js-breadcrumb-item-text');
+
+ if (textEl && textEl.scrollWidth > textEl.offsetWidth) {
+ el.setAttribute('title', el.textContent);
+ el.setAttribute('data-container', 'body');
+ el.classList.add('has-tooltip');
+ }
+};
+
+export default () => {
+ const breadcrumbs = document.querySelector('.js-breadcrumbs-list');
+
+ if (breadcrumbs) {
+ const topLevelLinks = [...breadcrumbs.children].filter(el => !el.classList.contains('dropdown'))
+ .map(el => el.querySelector('a'))
+ .filter(el => el);
+ const $expander = $('.js-breadcrumbs-collapsed-expander');
+
+ topLevelLinks.forEach(el => addTooltipToEl(el));
+
+ $expander.closest('.dropdown')
+ .on('show.bs.dropdown hide.bs.dropdown', (e) => {
+ $('.js-breadcrumbs-collapsed-expander', e.currentTarget).toggleClass('open')
+ .tooltip('hide');
+ });
+ }
+};
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 3dec4de06ec..6db0b18ae5a 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -41,7 +41,6 @@ import Issue from './issue';
import BindInOut from './behaviors/bind_in_out';
import DeleteModal from './branches/branches_delete_modal';
import Group from './group';
-import GroupName from './group_name';
import GroupsList from './groups_list';
import ProjectsList from './projects_list';
import setupProjectEdit from './project_edit';
@@ -489,6 +488,8 @@ import initChangesDropdown from './init_changes_dropdown';
initSettingsPanels();
break;
case 'projects:settings:ci_cd:show':
+ // Initialize expandable settings panels
+ initSettingsPanels();
case 'groups:settings:ci_cd:show':
new gl.ProjectVariables();
break;
@@ -554,9 +555,6 @@ import initChangesDropdown from './init_changes_dropdown';
case 'root':
new UserCallout();
break;
- case 'groups':
- new GroupName();
- break;
case 'profiles':
new NotificationsForm();
new NotificationsDropdown();
@@ -564,7 +562,6 @@ import initChangesDropdown from './init_changes_dropdown';
case 'projects':
new Project();
new ProjectAvatar();
- new GroupName();
switch (path[1]) {
case 'compare':
new CompareAutocomplete();
diff --git a/app/assets/javascripts/group_name.js b/app/assets/javascripts/group_name.js
deleted file mode 100644
index 6677391c689..00000000000
--- a/app/assets/javascripts/group_name.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import _ from 'underscore';
-
-export default class GroupName {
- constructor() {
- this.titleContainer = document.querySelector('.js-title-container');
- this.title = this.titleContainer.querySelector('.title');
-
- if (this.title) {
- this.titleWidth = this.title.offsetWidth;
- this.groupTitle = this.titleContainer.querySelector('.group-title');
- this.groups = this.titleContainer.querySelectorAll('.group-path');
- this.toggle = null;
- this.isHidden = false;
- this.init();
- }
- }
-
- init() {
- if (this.groups.length > 0) {
- this.groups[this.groups.length - 1].classList.remove('hidable');
- this.toggleHandler();
- window.addEventListener('resize', _.debounce(this.toggleHandler.bind(this), 100));
- }
- this.render();
- }
-
- toggleHandler() {
- if (this.titleWidth > this.titleContainer.offsetWidth) {
- if (!this.toggle) this.createToggle();
- this.showToggle();
- } else if (this.toggle) {
- this.hideToggle();
- }
- }
-
- createToggle() {
- this.toggle = document.createElement('button');
- this.toggle.setAttribute('type', 'button');
- this.toggle.className = 'text-expander group-name-toggle';
- this.toggle.setAttribute('aria-label', 'Toggle full path');
- this.toggle.innerHTML = '<i class="fa fa-ellipsis-h" aria-hidden="true"></i>';
- this.toggle.addEventListener('click', this.toggleGroups.bind(this));
- this.title.insertBefore(this.toggle, this.groupTitle);
- this.toggleGroups();
- }
-
- showToggle() {
- this.title.classList.add('wrap');
- this.toggle.classList.remove('hidden');
- if (this.isHidden) this.groupTitle.classList.add('hidden');
- }
-
- hideToggle() {
- this.title.classList.remove('wrap');
- this.toggle.classList.add('hidden');
- if (this.isHidden) this.groupTitle.classList.remove('hidden');
- }
-
- toggleGroups() {
- this.isHidden = !this.isHidden;
- this.groupTitle.classList.toggle('hidden');
- }
-
- render() {
- this.title.classList.remove('initializing');
- }
-}
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index f14458c8d41..0bc31a56684 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -144,6 +144,7 @@ import './smart_interval';
import './star';
import './subscription';
import './subscription_select';
+import initBreadcrumbs from './breadcrumb';
import './dispatcher';
@@ -181,6 +182,8 @@ $(function () {
var bootstrapBreakpoint = bp.getBreakpointSize();
var fitSidebarForSize;
+ initBreadcrumbs();
+
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 6b21def33a6..5f397f08936 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -829,6 +829,7 @@
}
}
+@include new-style-dropdown('.breadcrumbs-list .dropdown ');
@include new-style-dropdown('.js-namespace-select + ');
header.navbar-gitlab-new .header-content .dropdown-menu.projects-dropdown-menu {
diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss
index 4deb7431284..e4b52ab480d 100644
--- a/app/assets/stylesheets/new_nav.scss
+++ b/app/assets/stylesheets/new_nav.scss
@@ -1,6 +1,7 @@
@import "framework/variables";
@import 'framework/tw_bootstrap_variables';
@import "bootstrap/variables";
+@import "framework/mixins";
.content-wrapper.page-with-new-nav {
margin-top: $new-navbar-height;
@@ -422,109 +423,38 @@ header.navbar-gitlab-new {
.breadcrumbs {
display: flex;
- min-height: 61px;
+ min-height: 48px;
color: $gl-text-color;
- border-bottom: 1px solid $border-color;
-
- .dropdown-toggle-caret {
- position: relative;
- top: -1px;
- padding: 0 5px;
- color: $gl-text-color-secondary;
- font-size: 10px;
- line-height: 1;
- background: none;
- border: 0;
-
- &:focus {
- outline: 0;
- }
- }
-
- // TODO: fallback to global style
- .dropdown-menu {
- .divider {
- margin: 6px 0;
- }
-
- li {
- padding: 0 1px;
-
- a {
- border-radius: 0;
- padding: 8px 16px;
-
- &.is-focused,
- &:hover,
- &:active,
- &:focus {
- background-color: $gray-darker;
- }
- }
- }
- }
}
.breadcrumbs-container {
+ display: -webkit-flex;
display: flex;
width: 100%;
position: relative;
+ padding-top: $gl-padding;
+ padding-bottom: $gl-padding;
align-items: center;
-
- .dropdown-menu-projects {
- margin-top: -$gl-padding;
- margin-left: $gl-padding;
- }
+ border-bottom: 1px solid $border-color;
}
.breadcrumbs-links {
+ -webkit-flex: 1;
flex: 1;
min-width: 0;
align-self: center;
- color: $gl-text-color-quaternary;
-
- a {
- color: $gl-text-color-secondary;
-
- &:not(:first-child),
- &.group-path {
- margin-left: 4px;
- }
-
- &:not(:last-of-type),
- &.group-path {
- margin-right: 3px;
- }
- }
-
- .title {
- display: inline-block;
-
- > a {
- &:last-of-type:not(:first-child) {
- font-weight: $gl-font-weight-bold;
- }
- }
- }
+ color: $gl-text-color-secondary;
.avatar-tile {
- margin-right: 5px;
+ margin-right: 4px;
border: 1px solid $border-color;
border-radius: 50%;
vertical-align: sub;
-
- &.identicon {
- float: left;
- width: 16px;
- height: 16px;
- margin-top: 2px;
- font-size: 10px;
- }
}
.text-expander {
- margin-left: 4px;
- margin-right: 4px;
+ margin-left: 0;
+ margin-right: 2px;
> i {
position: relative;
@@ -533,37 +463,52 @@ header.navbar-gitlab-new {
}
}
-.breadcrumbs-extra {
+.breadcrumbs-list {
+ display: -webkit-flex;
display: flex;
- flex: 0 0 auto;
- margin-left: auto;
-}
+ flex-wrap: wrap;
+ margin-bottom: 0;
+ line-height: 16px;
-.breadcrumbs-sub-title {
- margin: 2px 0;
- font-size: 16px;
- font-weight: $gl-font-weight-normal;
- line-height: 1;
-
- ul {
- margin: 0;
- }
-
- li {
- display: inline-block;
+ > li {
+ display: flex;
+ align-items: center;
+ position: relative;
&:not(:last-child) {
- &::after {
- content: "/";
- margin: 0 2px 0 5px;
- color: rgba($black, .65);
- }
+ margin-right: 20px;
}
- &:last-child a {
- font-weight: $gl-font-weight-bold;
+ > a {
+ font-size: 12px;
+ color: currentColor;
}
}
+}
+
+.breadcrumb-item-text {
+ @include str-truncated(128px);
+}
+
+.breadcrumbs-list-angle {
+ position: absolute;
+ right: -12px;
+ top: 50%;
+ color: $gl-text-color-tertiary;
+ transform: translateY(-50%);
+}
+
+.breadcrumbs-extra {
+ display: flex;
+ flex: 0 0 auto;
+ margin-left: auto;
+}
+
+.breadcrumbs-sub-title {
+ margin: 0;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 1;
a {
color: $gl-text-color;
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index 90b0a543c5c..55e0343d0dc 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -45,7 +45,6 @@ $new-sidebar-collapsed-width: 50px;
margin-right: 2px;
a {
- border-bottom: 1px solid $border-color;
font-weight: $gl-font-weight-bold;
display: flex;
align-items: center;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index c051d37aad6..587a202d6dd 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -141,17 +141,17 @@
display: inline-block;
background: $white-light;
color: $gl-text-color-secondary;
- padding: 0 5px;
+ padding: 0 4px;
cursor: pointer;
border: 1px solid $border-gray-dark;
border-radius: $border-radius-default;
margin-left: 5px;
- font-size: $gl-font-size;
+ font-size: 12px;
line-height: $gl-font-size;
outline: none;
&.open {
- background: $gray-light;
+ background-color: darken($gray-light, 10%);
box-shadow: inset 0 0 2px rgba($black, 0.2);
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 45f2aed1531..e437bad4912 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -516,7 +516,7 @@ ul.notes {
}
.note-actions-item {
- margin-left: 15px;
+ margin-left: 12px;
display: flex;
align-items: center;
@@ -620,15 +620,25 @@ ul.notes {
.note-role {
position: relative;
- padding: 0 7px;
+ display: inline-block;
color: $notes-role-color;
font-size: 12px;
line-height: 20px;
- border: 1px solid $border-color;
- border-radius: $label-border-radius;
+ margin: 0 3px;
+
+ &.note-role-access {
+ padding: 0 7px;
+ border: 1px solid $border-color;
+ border-radius: $label-border-radius;
+ }
+
+ &.note-role-special {
+ text-shadow: 0 0 15px $gl-text-color-inverted;
+ }
}
+
/**
* Line note button on the side of diffs
*/
diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb
index bdc4332ae69..12a27cede75 100644
--- a/app/controllers/admin/logs_controller.rb
+++ b/app/controllers/admin/logs_controller.rb
@@ -1,6 +1,13 @@
class Admin::LogsController < Admin::ApplicationController
+ before_action :loggers
+
def show
- @loggers = [
+ end
+
+ private
+
+ def loggers
+ @loggers ||= [
Gitlab::AppLogger,
Gitlab::GitLogger,
Gitlab::EnvironmentLogger,
diff --git a/app/controllers/concerns/renders_notes.rb b/app/controllers/concerns/renders_notes.rb
index 41c3114ad1e..4791bc561a4 100644
--- a/app/controllers/concerns/renders_notes.rb
+++ b/app/controllers/concerns/renders_notes.rb
@@ -1,7 +1,8 @@
module RendersNotes
- def prepare_notes_for_rendering(notes)
+ def prepare_notes_for_rendering(notes, noteable = nil)
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
+ preload_first_time_contribution_for_authors(noteable, notes)
Banzai::NoteRenderer.render(notes, @project, current_user)
notes
@@ -19,4 +20,10 @@ module RendersNotes
def preload_noteable_for_regular_notes(notes)
ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
end
+
+ def preload_first_time_contribution_for_authors(noteable, notes)
+ return unless noteable.is_a?(Issuable) && noteable.first_contribution?
+
+ notes.each {|n| n.specialize_for_first_contribution!(noteable)}
+ end
end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 076076fd1b3..d83824fef06 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -9,8 +9,6 @@ class ProfilesController < Profiles::ApplicationController
end
def update
- user_params.except!(:email) if @user.external_email?
-
respond_to do |format|
result = Users::UpdateService.new(@user, user_params).execute
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index f637a9a803b..eb010923466 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -7,7 +7,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path
before_action :validate_artifacts!
- before_action :set_path_and_entry, only: [:file, :raw]
+ before_action :entry, only: [:file]
def download
if artifacts_file.file_storage?
@@ -41,7 +41,10 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
def raw
- send_artifacts_entry(build, @entry)
+ path = Gitlab::Ci::Build::Artifacts::Path
+ .new(params[:path])
+
+ send_artifacts_entry(build, path)
end
def keep
@@ -93,9 +96,8 @@ class Projects::ArtifactsController < Projects::ApplicationController
@artifacts_file ||= build.artifacts_file
end
- def set_path_and_entry
- @path = params[:path]
- @entry = build.artifacts_metadata_entry(@path)
+ def entry
+ @entry = build.artifacts_metadata_entry(params[:path])
render_404 unless @entry.exists?
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 6de125e7e80..1a775def506 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -127,7 +127,7 @@ class Projects::CommitController < Projects::ApplicationController
@discussions = commit.discussions
@notes = (@grouped_diff_discussions.values.flatten + @discussions).flat_map(&:notes)
- @notes = prepare_notes_for_rendering(@notes)
+ @notes = prepare_notes_for_rendering(@notes, @commit)
end
def assign_change_commit_vars
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index dc9e6f71152..ab9f132b502 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -85,7 +85,7 @@ class Projects::IssuesController < Projects::ApplicationController
@note = @project.notes.new(noteable: @issue)
@discussions = @issue.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
respond_to do |format|
format.html
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 330b7df4541..109418c73f7 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -61,6 +61,6 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
@use_legacy_diff_notes = !@merge_request.has_complete_diff_refs?
@grouped_diff_discussions = @merge_request.grouped_diff_discussions(@compare.diff_refs)
- @notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes), @merge_request)
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index dc7a94d824a..3aa5dadb5ca 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -61,12 +61,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
- @discussions = @merge_request.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
-
@noteable = @merge_request
@commits_count = @merge_request.commits_count
+ @discussions = @merge_request.discussions
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
+
labels
set_pipeline_variables
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index d07143d294f..7c19aa7bb23 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -64,7 +64,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@noteable = @snippet
@discussions = @snippet.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
render 'show'
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 8c3abd0a085..c1cdc7c9831 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -66,7 +66,7 @@ class SnippetsController < ApplicationController
@noteable = @snippet
@discussions = @snippet.discussions
- @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
respond_to do |format|
format.html do
diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb
index d1dc4d94560..089d9e3e387 100644
--- a/app/helpers/blame_helper.rb
+++ b/app/helpers/blame_helper.rb
@@ -11,11 +11,15 @@ module BlameHelper
end
def age_map_class(commit_date, duration)
- commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day
- # Numbers 0 to 10 come from this calculation, but only commits on the oldest
- # day get number 10 (all other numbers can be multiple days), so the range
- # is normalized to 0-9
- age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min
- "blame-commit-age-#{age_group}"
+ if duration[:started_days_ago] == 0
+ "blame-commit-age-0"
+ else
+ commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day
+ # Numbers 0 to 10 come from this calculation, but only commits on the oldest
+ # day get number 10 (all other numbers can be multiple days), so the range
+ # is normalized to 0-9
+ age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min
+ "blame-commit-age-#{age_group}"
+ end
end
end
diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb
index abe8edd6a8c..ee1b7ed083e 100644
--- a/app/helpers/breadcrumbs_helper.rb
+++ b/app/helpers/breadcrumbs_helper.rb
@@ -22,4 +22,16 @@ module BreadcrumbsHelper
@breadcrumb_title = title
end
+
+ def breadcrumb_list_item(link)
+ content_tag "li" do
+ link + icon("angle-right", class: "breadcrumbs-list-angle")
+ end
+ end
+
+ def add_to_breadcrumb_dropdown(link, location: :before)
+ @breadcrumb_dropdown_links ||= {}
+ @breadcrumb_dropdown_links[location] ||= []
+ @breadcrumb_dropdown_links[location] << link
+ end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index c4c41eac5db..eab1feb8a1f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -15,18 +15,20 @@ module GroupsHelper
@has_group_title = true
full_title = ''
- group.ancestors.reverse.each do |parent|
- full_title += group_title_link(parent, hidable: true)
-
- full_title += '<span class="hidable"> / </span>'.html_safe
+ group.ancestors.reverse.each_with_index do |parent, index|
+ if index > 0
+ add_to_breadcrumb_dropdown(group_title_link(parent, hidable: false, show_avatar: true), location: :before)
+ else
+ full_title += breadcrumb_list_item group_title_link(parent, hidable: false)
+ end
end
- full_title += group_title_link(group)
- full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path') if name
+ full_title += render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :before, title: _("Show parent subgroups")
- content_tag :span, class: 'group-title' do
- full_title.html_safe
- end
+ full_title += breadcrumb_list_item group_title_link(group)
+ full_title += ' &middot; '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path breadcrumb-item-text js-breadcrumb-item-text') if name
+
+ full_title.html_safe
end
def projects_lfs_status(group)
@@ -65,11 +67,11 @@ module GroupsHelper
private
- def group_title_link(group, hidable: false)
- link_to(group_path(group), class: "group-path #{'hidable' if hidable}") do
+ def group_title_link(group, hidable: false, show_avatar: false)
+ link_to(group_path(group), class: "group-path breadcrumb-item-text js-breadcrumb-item-text #{'hidable' if hidable}") do
output =
- if !Rails.env.test?
- image_tag(group_icon(group), class: "avatar-tile", width: 16, height: 16)
+ if (group.try(:avatar_url) || show_avatar) && !Rails.env.test?
+ image_tag(group_icon(group), class: "avatar-tile", width: 15, height: 15)
else
""
end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 717abf2082d..ce2999e6696 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -126,22 +126,20 @@ module IssuablesHelper
end
def issuable_meta(issuable, project, text)
- output = content_tag(:strong, class: "identifier") do
- concat("#{text} ")
- concat(to_url_reference(issuable))
- end
-
- output << " opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
+ output = ""
+ output << "Opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe
output << content_tag(:strong) do
author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "hidden-xs", tooltip: true)
author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "hidden-sm hidden-md hidden-lg")
end
output << "&ensp;".html_safe
+ output << content_tag(:span, (issuable_first_contribution_icon if issuable.first_contribution?), class: 'has-tooltip', title: _('1st contribution!'))
+
output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "hidden-xs hidden-sm")
output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "hidden-md hidden-lg")
- output
+ output.html_safe
end
def issuable_todo(issuable)
@@ -173,6 +171,13 @@ module IssuablesHelper
html.html_safe
end
+ def issuable_first_contribution_icon
+ content_tag(:span, class: 'fa-stack') do
+ concat(icon('certificate', class: "fa-stack-2x"))
+ concat(content_tag(:strong, '1', class: 'fa-inverse fa-stack-1x'))
+ end
+ end
+
def assigned_issuables_count(issuable_type)
case issuable_type
when :issues
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 083ace65b09..ce028195e51 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -73,7 +73,7 @@ module NotesHelper
end
def note_max_access_for_user(note)
- note.project.team.human_max_access(note.author_id)
+ note.project.team.max_member_access(note.author_id)
end
def discussion_path(discussion)
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index d83c7411c9d..5946c475835 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -80,7 +80,9 @@ module PageLayoutHelper
@header_title = title
@header_title_url = title_url
else
- @header_title_url ? link_to(@header_title, @header_title_url) : @header_title
+ return @header_title unless @header_title_url
+
+ breadcrumb_list_item(link_to(@header_title, @header_title_url))
end
end
diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb
index 45238f12ac7..5a4fda0724c 100644
--- a/app/helpers/profiles_helper.rb
+++ b/app/helpers/profiles_helper.rb
@@ -1,7 +1,12 @@
module ProfilesHelper
- def email_provider_label
- return unless current_user.external_email?
-
- current_user.email_provider.present? ? Gitlab::OAuth::Provider.label_for(current_user.email_provider) : "LDAP"
+ def attribute_provider_label(attribute)
+ user_synced_attributes_metadata = current_user.user_synced_attributes_metadata
+ if user_synced_attributes_metadata&.synced?(attribute)
+ if user_synced_attributes_metadata.provider
+ Gitlab::OAuth::Provider.label_for(user_synced_attributes_metadata.provider)
+ else
+ 'LDAP'
+ end
+ end
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cec7656773c..86665ea2aec 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -54,25 +54,28 @@ module ProjectsHelper
def project_title(project)
namespace_link =
if project.group
- group_title(project.group)
+ group_title(project.group, nil, nil)
else
owner = project.namespace.owner
link_to(simple_sanitize(owner.name), user_path(owner))
end
- project_link = link_to project_path(project), { class: "project-item-select-holder" } do
+ project_link = link_to project_path(project) do
output =
- if !Rails.env.test?
- project_icon(project, alt: project.name, class: 'avatar-tile', width: 16, height: 16)
+ if project.avatar_url && !Rails.env.test?
+ project_icon(project, alt: project.name, class: 'avatar-tile', width: 15, height: 15)
else
""
end
- output << simple_sanitize(project.name)
+ output << content_tag("span", simple_sanitize(project.name), class: "breadcrumb-item-text js-breadcrumb-item-text")
output.html_safe
end
- "#{namespace_link} / #{project_link}".html_safe
+ namespace_link = breadcrumb_list_item(namespace_link) unless project.group
+ project_link = breadcrumb_list_item project_link
+
+ "#{namespace_link} #{project_link}".html_safe
end
def remove_project_message(project)
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 99212a3438f..815fab9e061 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -10,4 +10,15 @@ module WikiHelper
.map { |dir_or_page| WikiPage.unhyphenize(dir_or_page).capitalize }
.join(' / ')
end
+
+ def wiki_breadcrumb_dropdown_links(page_slug)
+ page_slug_split = page_slug.split('/')
+ page_slug_split.pop(1)
+ current_slug = ""
+ page_slug_split
+ .map do |dir_or_page|
+ current_slug = "#{current_slug}#{dir_or_page}/"
+ add_to_breadcrumb_dropdown link_to(WikiPage.unhyphenize(dir_or_page).capitalize, project_wiki_path(@project, current_slug)), location: :after
+ end
+ end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 681c3241dbb..265f6e48540 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -334,4 +334,11 @@ module Issuable
metrics = self.metrics || create_metrics
metrics.record!
end
+
+ ##
+ # Override in issuable specialization
+ #
+ def first_contribution?
+ false
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index b82f49d7073..2a56bab48a3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -960,6 +960,12 @@ class MergeRequest < ActiveRecord::Base
Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache
end
+ def first_contribution?
+ return false if project.team.max_member_access(author_id) > Gitlab::Access::GUEST
+
+ project.merge_requests.merged.where(author_id: author_id).empty?
+ end
+
private
def write_ref
diff --git a/app/models/note.rb b/app/models/note.rb
index 1073c115630..f44590e2144 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -15,6 +15,16 @@ class Note < ActiveRecord::Base
include IgnorableColumn
include Editable
+ module SpecialRole
+ FIRST_TIME_CONTRIBUTOR = :first_time_contributor
+
+ class << self
+ def values
+ constants.map {|const| self.const_get(const)}
+ end
+ end
+ end
+
ignore_column :original_discussion_id
cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true
@@ -32,9 +42,12 @@ class Note < ActiveRecord::Base
# Banzai::ObjectRenderer
attr_accessor :user_visible_reference_count
- # Attribute used to store the attributes that have ben changed by quick actions.
+ # Attribute used to store the attributes that have been changed by quick actions.
attr_accessor :commands_changes
+ # A special role that may be displayed on issuable's discussions
+ attr_accessor :special_role
+
default_value_for :system, false
attr_mentionable :note, pipeline: :note
@@ -141,6 +154,10 @@ class Note < ActiveRecord::Base
.group(:noteable_id)
.where(noteable_type: type, noteable_id: ids)
end
+
+ def has_special_role?(role, note)
+ note.special_role == role
+ end
end
def cross_reference?
@@ -206,6 +223,22 @@ class Note < ActiveRecord::Base
super(noteable_type.to_s.classify.constantize.base_class.to_s)
end
+ def special_role=(role)
+ raise "Role is undefined, #{role} not found in #{SpecialRole.values}" unless SpecialRole.values.include?(role)
+
+ @special_role = role
+ end
+
+ def has_special_role?(role)
+ self.class.has_special_role?(role, self)
+ end
+
+ def specialize_for_first_contribution!(noteable)
+ return unless noteable.author_id == self.author_id
+
+ self.special_role = Note::SpecialRole::FIRST_TIME_CONTRIBUTOR
+ end
+
def editable?
!system?
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 674eacd28e8..09049824ff7 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -150,7 +150,7 @@ class ProjectTeam
end
def human_max_access(user_id)
- Gitlab::Access.options_with_owner.key(max_member_access(user_id))
+ Gitlab::Access.human_access(max_member_access(user_id))
end
# Determine the maximum access level for a group of users in bulk.
diff --git a/app/models/user.rb b/app/models/user.rb
index c5b5f09722f..105eb62f1fa 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -15,10 +15,12 @@ class User < ActiveRecord::Base
include IgnorableColumn
include FeatureGate
include CreatedAtFilterable
+ include IgnorableColumn
DEFAULT_NOTIFICATION_LEVEL = :participating
- ignore_column :authorized_projects_populated
+ ignore_column :external_email
+ ignore_column :email_provider
add_authentication_token_field :authentication_token
add_authentication_token_field :incoming_email_token
@@ -85,6 +87,7 @@ class User < ActiveRecord::Base
has_many :identities, dependent: :destroy, autosave: true # rubocop:disable Cop/ActiveRecordDependent
has_many :u2f_registrations, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :chat_names, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_one :user_synced_attributes_metadata, autosave: true
# Groups
has_many :members, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -161,6 +164,7 @@ class User < ActiveRecord::Base
after_update :update_emails_with_primary_email, if: :email_changed?
before_save :ensure_authentication_token, :ensure_incoming_email_token
before_save :ensure_user_rights_and_limits, if: :external_changed?
+ before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) }
after_save :ensure_namespace_correct
after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') }
after_initialize :set_projects_limit
@@ -1045,6 +1049,22 @@ class User < ActiveRecord::Base
self.email == email
end
+ def sync_attribute?(attribute)
+ return true if ldap_user? && attribute == :email
+
+ attributes = Gitlab.config.omniauth.sync_profile_attributes
+
+ if attributes.is_a?(Array)
+ attributes.include?(attribute.to_s)
+ else
+ attributes
+ end
+ end
+
+ def read_only_attribute?(attribute)
+ user_synced_attributes_metadata&.read_only?(attribute)
+ end
+
protected
# override, from Devise::Validatable
diff --git a/app/models/user_synced_attributes_metadata.rb b/app/models/user_synced_attributes_metadata.rb
new file mode 100644
index 00000000000..9f374304164
--- /dev/null
+++ b/app/models/user_synced_attributes_metadata.rb
@@ -0,0 +1,25 @@
+class UserSyncedAttributesMetadata < ActiveRecord::Base
+ belongs_to :user
+
+ validates :user, presence: true
+
+ SYNCABLE_ATTRIBUTES = %i[name email location].freeze
+
+ def read_only?(attribute)
+ Gitlab.config.omniauth.sync_profile_from_provider && synced?(attribute)
+ end
+
+ def read_only_attributes
+ return [] unless Gitlab.config.omniauth.sync_profile_from_provider
+
+ SYNCABLE_ATTRIBUTES.select { |key| synced?(key) }
+ end
+
+ def synced?(attribute)
+ read_attribute("#{attribute}_synced")
+ end
+
+ def set_attribute_synced(attribute, value)
+ write_attribute("#{attribute}_synced", value)
+ end
+end
diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb
index 2f9855273dc..6188b8a4349 100644
--- a/app/services/users/update_service.rb
+++ b/app/services/users/update_service.rb
@@ -34,6 +34,10 @@ module Users
private
def assign_attributes(&block)
+ if @user.user_synced_attributes_metadata
+ params.except!(*@user.user_synced_attributes_metadata.read_only_attributes)
+ end
+
@user.assign_attributes(params) if params.any?
end
end
diff --git a/app/views/admin/applications/edit.html.haml b/app/views/admin/applications/edit.html.haml
index 13b583e6072..13c408914bb 100644
--- a/app/views/admin/applications/edit.html.haml
+++ b/app/views/admin/applications/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Applications", admin_applications_path
+- breadcrumb_title @application.name
- page_title "Edit", @application.name, "Applications"
%h3.page-title Edit application
diff --git a/app/views/admin/cohorts/index.html.haml b/app/views/admin/cohorts/index.html.haml
index be8644c0ca6..bff53da1d9a 100644
--- a/app/views/admin/cohorts/index.html.haml
+++ b/app/views/admin/cohorts/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Cohorts"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8e94e68bc11..069f8f89e0b 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -1,4 +1,5 @@
- @no_container = true
+- breadcrumb_title "Dashboard"
= render "admin/dashboard/head"
%div{ class: container_class }
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 2aadc071c75..3e02f7b1e16 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Groups", admin_groups_path
+- breadcrumb_title @group.name
- page_title @group.name, "Groups"
%h3.page-title
Group: #{@group.full_name}
diff --git a/app/views/admin/hooks/edit.html.haml b/app/views/admin/hooks/edit.html.haml
index 665e8c7e74f..efb15ccc8df 100644
--- a/app/views/admin/hooks/edit.html.haml
+++ b/app/views/admin/hooks/edit.html.haml
@@ -1,3 +1,4 @@
+- add_to_breadcrumbs "System Hooks", admin_hooks_path
- page_title 'Edit System Hook'
%h3.page-title
Edit System Hook
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 09be17f07be..aa6e9db3900 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Jobs"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/labels/edit.html.haml b/app/views/admin/labels/edit.html.haml
index 309aedceded..96f0d404ac4 100644
--- a/app/views/admin/labels/edit.html.haml
+++ b/app/views/admin/labels/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Labels", admin_labels_path
+- breadcrumb_title "Edit Label"
- page_title "Edit", @label.name, "Labels"
%h3.page-title
Edit Label
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 7b1b15cfeb8..ab4165c0bf2 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Projects", admin_projects_path
+- breadcrumb_title @project.name_with_namespace
- page_title @project.name_with_namespace, "Projects"
%h3.page-title
Project: #{@project.name_with_namespace}
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 126550ee10e..6793ce557c4 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Runners"
- @no_container = true
= render "admin/dashboard/head"
diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml
index 53d970e33c1..512176649e6 100644
--- a/app/views/admin/services/edit.html.haml
+++ b/app/views/admin/services/edit.html.haml
@@ -1,2 +1,4 @@
+- add_to_breadcrumbs "Service Templates", admin_application_settings_services_path
+- breadcrumb_title @service.title
- page_title @service.title, "Service Templates"
= render 'form'
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index b556ff056c0..98ff592eb64 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title @user.name, "Users"
= render 'admin/users/head'
diff --git a/app/views/ci/variables/_content.html.haml b/app/views/ci/variables/_content.html.haml
index 98f618ca3b8..fbfe3e56588 100644
--- a/app/views/ci/variables/_content.html.haml
+++ b/app/views/ci/variables/_content.html.haml
@@ -1,9 +1,3 @@
-%h4.prepend-top-0
- Secret variables
- = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'secret-variables'), target: '_blank'
-%p
- These variables will be set to environment by the runner, and could be protected by exposing only to protected branches or tags.
-%p
- So you can use them for passwords, secret keys or whatever you want.
-%p
- The value of the variable can be visible in job log if explicitly asked to do so.
+%p.append-bottom-default
+ Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags.
+ You can use variables for passwords, secret keys, or whatever you want.
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index 007c2344b5a..2bac69bc536 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -1,7 +1,5 @@
.row.prepend-top-default.append-bottom-default
- .col-lg-4
- = render "ci/variables/content"
- .col-lg-8
+ .col-lg-12
%h5.prepend-top-0
Add a variable
= render "ci/variables/form", btn_text: "Add new variable"
diff --git a/app/views/ci/variables/_show.html.haml b/app/views/ci/variables/_show.html.haml
index 2bfb290629d..6d75ae96124 100644
--- a/app/views/ci/variables/_show.html.haml
+++ b/app/views/ci/variables/_show.html.haml
@@ -4,6 +4,6 @@
.col-lg-3
= render "ci/variables/content"
.col-lg-9
- %h5.prepend-top-0
+ %h4.prepend-top-0
Update variable
= render "ci/variables/form", btn_text: "Save variable"
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 9ebb3894c55..839f23e69fd 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "General Settings"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
.panel-heading
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 7a2e688a114..7f3f2f707f7 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Projects"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml
index bf36baf48ab..9f9ae01e7c5 100644
--- a/app/views/groups/settings/ci_cd/show.html.haml
+++ b/app/views/groups/settings/ci_cd/show.html.haml
@@ -1,4 +1,5 @@
-- page_title "Pipelines"
+- breadcrumb_title "CI / CD Settings"
+- page_title "CI / CD"
= render "groups/settings_head"
= render 'ci/variables/index'
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index e07f61c94e4..f4f76887422 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- breadcrumb_title "Group"
+- breadcrumb_title "Details"
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
diff --git a/app/views/groups/subgroups.html.haml b/app/views/groups/subgroups.html.haml
index 8f0724c0677..7abc84412c6 100644
--- a/app/views/groups/subgroups.html.haml
+++ b/app/views/groups/subgroups.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Details"
- @no_container = true
= render 'head'
diff --git a/app/views/layouts/nav/_breadcrumbs.html.haml b/app/views/layouts/nav/_breadcrumbs.html.haml
index ff0f6489861..feffd7707dc 100644
--- a/app/views/layouts/nav/_breadcrumbs.html.haml
+++ b/app/views/layouts/nav/_breadcrumbs.html.haml
@@ -1,28 +1,22 @@
-- breadcrumb_link = breadcrumb_title_link
- container = @no_breadcrumb_container ? 'container-fluid' : container_class
- hide_top_links = @hide_top_links || false
-%nav.breadcrumbs{ role: "navigation" }
+%nav.breadcrumbs{ role: "navigation", class: [container, @content_class] }
.breadcrumbs-container{ class: [container, @content_class] }
- if defined?(@left_sidebar)
= button_tag class: 'toggle-mobile-nav', type: 'button' do
%span.sr-only Open sidebar
= icon ('bars')
.breadcrumbs-links.js-title-container
- - unless hide_top_links
- .title
- = link_to "GitLab", root_path
- \/
- - if content_for?(:header_title_before)
- = yield :header_title_before
- \/
+ %ul.list-unstyled.breadcrumbs-list.js-breadcrumbs-list
+ - unless hide_top_links
= header_title
- %h2.breadcrumbs-sub-title
- %ul.list-unstyled
- - if @breadcrumbs_extra_links
- - @breadcrumbs_extra_links.each do |extra|
- %li= link_to extra[:text], extra[:link]
- %li= link_to @breadcrumb_title, breadcrumb_link
+ - if @breadcrumbs_extra_links
+ - @breadcrumbs_extra_links.each do |extra|
+ = breadcrumb_list_item link_to(extra[:text], extra[:link])
+ = render "layouts/nav/breadcrumbs/collapsed_dropdown", location: :after
+ %li
+ %h2.breadcrumbs-sub-title= @breadcrumb_title
- if content_for?(:breadcrumbs_extra)
.breadcrumbs-extra.hidden-xs= yield :breadcrumbs_extra
= yield :header_content
diff --git a/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
new file mode 100644
index 00000000000..28022eebb19
--- /dev/null
+++ b/app/views/layouts/nav/breadcrumbs/_collapsed_dropdown.html.haml
@@ -0,0 +1,11 @@
+- dropdown_location = local_assigns.fetch(:location, nil)
+- button_tooltip = local_assigns.fetch(:title, _("Show parent pages"))
+- if defined?(@breadcrumb_dropdown_links) && @breadcrumb_dropdown_links.key?(dropdown_location)
+ %li.dropdown
+ %button.text-expander.has-tooltip.js-breadcrumbs-collapsed-expander{ type: "button", data: { toggle: "dropdown", container: "body" }, "aria-label": button_tooltip, title: button_tooltip }
+ = icon("ellipsis-h")
+ = icon("angle-right", class: "breadcrumbs-list-angle")
+ .dropdown-menu
+ %ul
+ - @breadcrumb_dropdown_links[dropdown_location].each_with_index do |link, index|
+ %li{ style: "text-indent: #{[index * 16, 60].min}px;" }= link
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 985bb79508f..c606b5a1e6c 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Edit Password"
- page_title "Password"
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 2216708d354..06bb72b9f0d 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "Access Tokens"
- page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index a8ae0b92334..35ad280b037 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -1,4 +1,4 @@
-- breadcrumb_title "Profile"
+- breadcrumb_title "Edit Profile"
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
@@ -45,12 +45,15 @@
Some options are unavailable for LDAP accounts
.col-lg-8
.row
- = f.text_field :name, required: true, wrapper: { class: 'col-md-9' },
- help: 'Enter your name, so people you know can recognize you.'
+ - if @user.read_only_attribute?(:name)
+ = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9' },
+ help: "Your name was automatically set based on your #{ attribute_provider_label(:name) } account, so people you know can recognize you."
+ - else
+ = f.text_field :name, required: true, wrapper: { class: 'col-md-9' }, help: "Enter your name, so people you know can recognize you."
= f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
- - if @user.external_email?
- = f.text_field :email, required: true, readonly: true, help: "Your email address was automatically set based on your #{email_provider_label} account."
+ - if @user.read_only_attribute?(:email)
+ = f.text_field :email, required: true, readonly: true, help: "Your email address was automatically set based on your #{ attribute_provider_label(:email) } account."
- else
= f.text_field :email, required: true, value: (@user.email unless @user.temp_oauth_email?),
help: user_email_help_text(@user)
@@ -64,7 +67,10 @@
= f.text_field :linkedin
= f.text_field :twitter
= f.text_field :website_url, label: 'Website'
- = f.text_field :location
+ - if @user.read_only_attribute?(:location)
+ = f.text_field :location, readonly: true, help: "Your location was automatically set based on your #{ attribute_provider_label(:location) } account."
+ - else
+ = f.text_field :location
= f.text_field :organization
= f.text_area :bio, rows: 4, maxlength: 250, help: 'Tell us about yourself in fewer than 250 characters.'
.prepend-top-default.append-bottom-default
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index 2897c955c78..f80dadb8037 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,7 +1,7 @@
- @no_container = true
-- add_to_breadcrumbs(_("Project"), project_path(@project))
- page_title _("Activity")
+
= render "projects/head"
= render 'projects/last_push'
diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml
index a33743c2f57..4cc3218d967 100644
--- a/app/views/projects/artifacts/browse.html.haml
+++ b/app/views/projects/artifacts/browse.html.haml
@@ -1,8 +1,12 @@
+- breadcrumb_title _('Artifacts')
- page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs'
= render "projects/pipelines/head"
= render "projects/jobs/header", show_controls: false
+- add_to_breadcrumbs(_('Jobs'), project_jobs_path(@project))
+- add_to_breadcrumbs("##{@build.id}", project_jobs_path(@project))
+
.tree-holder
.nav-block
%ul.breadcrumb.repo-breadcrumb
diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml
index 67d9db9aefe..303e20e8780 100644
--- a/app/views/projects/boards/_show.html.haml
+++ b/app/views/projects/boards/_show.html.haml
@@ -1,8 +1,8 @@
- @no_breadcrumb_container = true
- @no_container = true
- @content_class = "issue-boards-content"
+- breadcrumb_title "Issue Board"
- page_title "Boards"
-- add_to_breadcrumbs("Issues", project_issues_path(@project))
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index b1834de0bad..73583c6bbc2 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,7 +1,5 @@
- @no_container = true
- page_title "Branches"
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
-
= render "projects/commits/head"
%div{ class: container_class }
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index 07c83c0a590..717de85c5d2 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Commits", project_commits_path(@project)
+- breadcrumb_title @commit.short_id
- container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : ''
- limited_container_width = fluid_layout ? '' : 'limit-container-width'
- @content_class = limited_container_width
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 0f048079ef5..e873b931683 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -5,8 +5,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
-
= content_for :sub_nav do
= render "head"
diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml
index ecef91855af..2632fea6eba 100644
--- a/app/views/projects/compare/index.html.haml
+++ b/app/views/projects/compare/index.html.haml
@@ -1,6 +1,6 @@
- @no_container = true
+- breadcrumb_title "Compare Revisions"
- page_title "Compare"
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class }
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index eca733a933a..7cc42455394 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -1,7 +1,6 @@
- @no_container = true
-- breadcrumb_title "Compare"
+- add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class }
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index 5691024b997..8d008be5aae 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,6 +1,5 @@
- @no_container = true
- page_title "Cycle Analytics"
-- add_to_breadcrumbs("Project", project_path(@project))
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('cycle_analytics')
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 9e26bdecd31..994119051d2 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -1,3 +1,4 @@
+- breadcrumb_title "General Settings"
- page_title "General"
- @content_class = "limit-container-width" unless fluid_layout
- expanded = Rails.env.test?
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index d17709380d5..5e980314307 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,4 +1,5 @@
- @no_container = true
+- breadcrumb_title "Details"
= render partial: 'flash_messages', locals: { project: @project }
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 0ce0f5465fc..c35d1b5aaee 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Environments", project_environments_path(@project)
+- breadcrumb_title @environment.name
- page_title "Environments"
= render "projects/pipelines/head"
diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml
index 44bd8d1f9ad..f0ef647ddb3 100644
--- a/app/views/projects/graphs/charts.html.haml
+++ b/app/views/projects/graphs/charts.html.haml
@@ -1,6 +1,5 @@
- @no_container = true
- page_title "Charts"
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
- content_for :page_specific_javascripts do
= webpack_bundle_tag('common_d3')
= webpack_bundle_tag('graphs')
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 2f60078796e..08b38428b50 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -5,8 +5,6 @@
= webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_show')
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
-
= render 'projects/commits/head'
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 04b4ed95a2d..fbaf88356bf 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- add_to_breadcrumbs "Issues", project_issues_path(@project)
+- breadcrumb_title @issue.to_reference
- page_title "#{@issue.title} (#{@issue.to_reference})", "Issues"
- page_description @issue.description
- page_card_attributes @issue.card_attributes
diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml
index 9751de0f938..8604c7d3ea4 100644
--- a/app/views/projects/jobs/index.html.haml
+++ b/app/views/projects/jobs/index.html.haml
@@ -2,8 +2,6 @@
- page_title "Jobs"
= render "projects/pipelines/head"
-- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-
%div{ class: container_class }
.top-area
- build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) }
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index fa086413fbe..975c08c06e6 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Jobs", project_jobs_path(@project)
+- breadcrumb_title "##{@build.id}"
- page_title "#{@build.name} (##{@build.id})", "Jobs"
= render "projects/pipelines/head"
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index d27e121beb4..c2d16f7e731 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- add_to_breadcrumbs "Merge Requests", project_merge_requests_path(@project)
+- breadcrumb_title @merge_request.to_reference
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests"
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 0bf0e11c107..1f5f18801ad 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Milestones", project_milestones_path(@project)
+- breadcrumb_title @milestone.title
- page_title @milestone.title, "Milestones"
- page_description @milestone.description
= render "shared/mr_head"
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 2defd45a0b2..e29cb277389 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -2,7 +2,6 @@
- page_title "Graph", @ref
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('network')
-- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
= render "head"
%div{ class: container_class }
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index fb07141d2ac..de76832331a 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -1,6 +1,8 @@
-- access = note_max_access_for_user(note)
-- if access
- %span.note-role= access
+- if note.has_special_role?(Note::SpecialRole::FIRST_TIME_CONTRIBUTOR)
+ %span.note-role.note-role-special.has-tooltip{ title: _("This is the author's first Merge Request to this project. Handle with care.") }
+ = issuable_first_contribution_icon
+- if access = note_max_access_for_user(note)
+ %span.note-role.note-role-access= Gitlab::Access.human_access(access)
- if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note)
diff --git a/app/views/projects/pipeline_schedules/edit.html.haml b/app/views/projects/pipeline_schedules/edit.html.haml
index 9b2a7b5821d..d95fa6da903 100644
--- a/app/views/projects/pipeline_schedules/edit.html.haml
+++ b/app/views/projects/pipeline_schedules/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs _("Schedules"), pipeline_schedules_path(@project)
+- breadcrumb_title "##{@schedule.id}"
- page_title _("Edit"), @schedule.description, _("Pipeline Schedule")
%h3.page-title
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 83b51bae73d..d9957b54a4d 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -1,4 +1,4 @@
-- breadcrumb_title "Schedules"
+- breadcrumb_title _("Schedules")
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
@@ -11,8 +11,6 @@
- content_for :breadcrumbs_extra do
= link_to _('New schedule'), new_namespace_project_pipeline_schedule_path(@project.namespace, @project), class: 'btn btn-create'
-- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
-
= render "projects/pipelines/head"
%div{ class: container_class }
diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml
index d710ba92cdd..487ac87186d 100644
--- a/app/views/projects/pipelines/charts.html.haml
+++ b/app/views/projects/pipelines/charts.html.haml
@@ -1,6 +1,6 @@
- @no_container = true
+- breadcrumb_title "CI / CD Charts"
- page_title _("Charts"), _("Pipelines")
-- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index 63f85fc69a2..7cc9fe79afd 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Pipelines", project_pipelines_path(@project)
+- breadcrumb_title "##{@pipeline.id}"
- page_title "Pipeline"
= render "projects/pipelines/head"
diff --git a/app/views/projects/pipelines_settings/_badge.html.haml b/app/views/projects/pipelines_settings/_badge.html.haml
index 3de518c8b9a..e8028059487 100644
--- a/app/views/projects/pipelines_settings/_badge.html.haml
+++ b/app/views/projects/pipelines_settings/_badge.html.haml
@@ -1,34 +1,32 @@
%div{ class: badge.title.gsub(' ', '-') }
- .col-lg-4.profile-settings-sidebar
- %h4.prepend-top-0
+ .col-lg-12
+ %h4
= badge.title.capitalize
- .col-lg-8
- .prepend-top-10
- .panel.panel-default
- .panel-heading
- %b
- = badge.title.capitalize
- &middot;
- = badge.to_html
- .pull-right
- = render 'shared/ref_switcher', destination: 'badges', align_right: true
- .panel-body
- .row
- .col-md-2.text-center
- Markdown
- .col-md-10.code.js-syntax-highlight
- = highlight('.md', badge.to_markdown)
- .row
- %hr
- .row
- .col-md-2.text-center
- HTML
- .col-md-10.code.js-syntax-highlight
- = highlight('.html', badge.to_html)
- .row
- %hr
- .row
- .col-md-2.text-center
- AsciiDoc
- .col-md-10.code.js-syntax-highlight
- = highlight('.adoc', badge.to_asciidoc)
+ .panel.panel-default
+ .panel-heading
+ %b
+ = badge.title.capitalize
+ &middot;
+ = badge.to_html
+ .pull-right
+ = render 'shared/ref_switcher', destination: 'badges', align_right: true
+ .panel-body
+ .row
+ .col-md-2.text-center
+ Markdown
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.md', badge.to_markdown)
+ .row
+ %hr
+ .row
+ .col-md-2.text-center
+ HTML
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.html', badge.to_html)
+ .row
+ %hr
+ .row
+ .col-md-2.text-center
+ AsciiDoc
+ .col-md-10.code.js-syntax-highlight
+ = highlight('.adoc', badge.to_asciidoc)
diff --git a/app/views/projects/pipelines_settings/_show.html.haml b/app/views/projects/pipelines_settings/_show.html.haml
index d407e187df0..8bf76b646f7 100644
--- a/app/views/projects/pipelines_settings/_show.html.haml
+++ b/app/views/projects/pipelines_settings/_show.html.haml
@@ -1,8 +1,5 @@
.row.prepend-top-default
- .col-lg-4.profile-settings-sidebar
- %h4.prepend-top-0
- Pipelines
- .col-lg-8
+ .col-lg-12
= form_for @project, url: project_pipelines_settings_path(@project) do |f|
%fieldset.builds-feature
- unless @repository.gitlab_ci_yml
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 5c3339cc749..25153fd0b6f 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,7 +1,5 @@
- page_title "Members"
-- add_to_breadcrumbs("Settings", edit_project_path(@project))
-
.row.prepend-top-default
.col-lg-12
%h4
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index 0a5a38a3694..c786298e341 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Tags", project_tags_path(@project)
+- breadcrumb_title @tag.name
- page_title "Edit", @tag.name, "Tags"
= render "projects/commits/head"
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index 2a829cd6c3d..eaf374bcb83 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -1,10 +1,54 @@
- @content_class = "limit-container-width" unless fluid_layout
-- page_title "Pipelines"
-- add_to_breadcrumbs("Settings", edit_project_path(@project))
+- page_title "CI / CD Settings"
+- page_title "CI / CD"
= render "projects/settings/head"
-= render 'projects/runners/index'
-= render 'ci/variables/index'
-= render 'projects/triggers/index'
-= render 'projects/pipelines_settings/show'
+- expanded = Rails.env.test?
+
+%section.settings
+ .settings-header
+ %h4
+ General pipelines settings
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Update your CI/CD configuration, like job timeout.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/pipelines_settings/show'
+
+%section.settings
+ .settings-header
+ %h4
+ Runners settings
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Register and see your runners for this project.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/runners/index'
+
+%section.settings
+ .settings-header
+ %h4
+ Secret variables
+ = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'secret-variables'), target: '_blank'
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ = render "ci/variables/content"
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'ci/variables/index'
+
+%section.settings
+ .settings-header
+ %h4
+ Pipeline triggers
+ %button.btn.js-settings-toggle
+ = expanded ? 'Collapse' : 'Expand'
+ %p
+ Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will
+ impersonate their associated user including their access to projects and their project
+ permissions.
+ .settings-content.no-animate{ class: ('expanded' if expanded) }
+ = render 'projects/triggers/index'
diff --git a/app/views/projects/settings/integrations/show.html.haml b/app/views/projects/settings/integrations/show.html.haml
index 1efa5907b3a..933daa7f549 100644
--- a/app/views/projects/settings/integrations/show.html.haml
+++ b/app/views/projects/settings/integrations/show.html.haml
@@ -1,6 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
+- breadcrumb_title "Integrations Settings"
- page_title 'Integrations'
-- add_to_breadcrumbs("Settings", edit_project_path(@project))
= render "projects/settings/head"
= render 'projects/hooks/index'
= render 'projects/services/index'
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index d4d461f6f22..6d4af72b8ea 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -1,6 +1,6 @@
+- breadcrumb_title "Repository Settings"
- page_title "Repository"
- @content_class = "limit-container-width" unless fluid_layout
-- add_to_breadcrumbs("Settings", edit_project_path(@project))
= render "projects/settings/head"
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index a9b39cedb1d..3f0a24cfe83 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,5 +1,5 @@
- @no_container = true
-- breadcrumb_title "Project"
+- breadcrumb_title "Details"
- @content_class = "limit-container-width" unless fluid_layout
= content_for :meta_tags do
diff --git a/app/views/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml
index d41cc8e0425..32844f5204a 100644
--- a/app/views/projects/snippets/edit.html.haml
+++ b/app/views/projects/snippets/edit.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Snippets", project_snippets_path(@project)
+- breadcrumb_title @snippet.to_reference
- page_title "Edit", "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
%h3.page-title
diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml
index d3e6b456f48..1359a815429 100644
--- a/app/views/projects/snippets/new.html.haml
+++ b/app/views/projects/snippets/new.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Snippets", project_snippets_path(@project)
+- breadcrumb_title "New"
- page_title "New Snippets"
%h3.page-title
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index d8e448dd2af..fda068f08c2 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -1,4 +1,6 @@
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
+- add_to_breadcrumbs "Snippets", dashboard_snippets_path
+- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header'
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index d02cd70f4c3..5d6eb4f4026 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Tags", project_tags_path(@project)
+- breadcrumb_title @tag.name
- page_title @tag.name, "Tags"
= render "projects/commits/head"
diff --git a/app/views/projects/triggers/_content.html.haml b/app/views/projects/triggers/_content.html.haml
index ea32eac2ae2..6c2d603d95d 100644
--- a/app/views/projects/triggers/_content.html.haml
+++ b/app/views/projects/triggers/_content.html.haml
@@ -1,14 +1,8 @@
-%h4.prepend-top-0
- Triggers
-%p.prepend-top-20
- Triggers can force a specific branch or tag to get rebuilt with an API call. These tokens will
- impersonate their associated user including their access to projects and their project
- permissions.
-%p.prepend-top-20
+%p.append-bottom-default
Triggers with the
%span.label.label-primary legacy
label do not have an associated user and only have access to the current project.
-%p.append-bottom-0
+ %br
= succeed '.' do
Learn more in the
= link_to 'triggers documentation', help_page_path('ci/triggers/README'), target: '_blank'
diff --git a/app/views/projects/triggers/_index.html.haml b/app/views/projects/triggers/_index.html.haml
index e9a2f803edd..0f655e4ed83 100644
--- a/app/views/projects/triggers/_index.html.haml
+++ b/app/views/projects/triggers/_index.html.haml
@@ -1,7 +1,6 @@
.row.prepend-top-default.append-bottom-default.triggers-container
- .col-lg-4
+ .col-lg-12
= render "projects/triggers/content"
- .col-lg-8
.panel.panel-default
.panel-heading
%h4.panel-title
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index dece1fad0bb..d533c611a38 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -1,4 +1,6 @@
- @no_container = true
+- add_to_breadcrumbs "Wiki", get_project_wiki_path(@project)
+- breadcrumb_title "Pages"
- page_title "Pages", "Wiki"
%div{ class: container_class }
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 9dadd685ea2..b066a812ec8 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -1,14 +1,13 @@
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout
-- breadcrumb_title "Wiki"
+- breadcrumb_title @page.title.capitalize
+- wiki_breadcrumb_dropdown_links(@page.slug)
- page_title @page.title.capitalize, "Wiki"
+- add_to_breadcrumbs "Wiki", get_project_wiki_path(@project)
.wiki-page-header.has-sidebar-toggle
%button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
- .wiki-breadcrumb
- %span= breadcrumb(@page.slug)
-
.nav-text
%h2.wiki-page-title= @page.title.capitalize
%span.wiki-last-edit-by
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 17b34c5eeb3..119d189f21d 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -3,10 +3,8 @@
%span.sr-only
= visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
- %strong.item-title
- Snippet #{@snippet.to_reference}
%span.creator
- authored
+ Authored
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "hidden-xs")}
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 706f13dd004..578327883e5 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,5 +1,7 @@
- @hide_top_links = true
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
+- add_to_breadcrumbs "Snippets", dashboard_snippets_path
+- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header'