Commit a257d964 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge remote-tracking branch 'ee-com/master' into ce-to-ee

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parents 465ff093 509bcaaf
......@@ -398,7 +398,6 @@ db:migrate:reset-mysql:
.migration-paths: &migration-paths
<<: *dedicated-runner
<<: *only-canonical-masters
<<: *pull-cache
stage: test
variables:
......
......@@ -336,7 +336,7 @@ group :development, :test do
# Generate Fake data
gem 'ffaker', '~> 2.4'
gem 'capybara', '~> 2.6.2'
gem 'capybara', '~> 2.15.0'
gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.9.0'
......
......@@ -108,9 +108,9 @@ GEM
bundler (~> 1.2)
thor (~> 0.18)
byebug (9.0.6)
capybara (2.6.2)
capybara (2.15.1)
addressable
mime-types (>= 1.16)
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
......@@ -506,6 +506,7 @@ GEM
method_source (0.8.2)
mime-types (2.99.3)
mimemagic (0.3.0)
mini_mime (0.1.4)
mini_portile2 (2.2.0)
minitest (5.7.0)
mmap2 (2.2.7)
......@@ -977,7 +978,7 @@ GEM
expression_parser
rinku
xml-simple (1.1.5)
xpath (2.0.0)
xpath (2.1.0)
nokogiri (~> 1.3)
PLATFORMS
......@@ -1009,7 +1010,7 @@ DEPENDENCIES
browser (~> 2.2)
bullet (~> 5.5.0)
bundler-audit (~> 0.5.0)
capybara (~> 2.6.2)
capybara (~> 2.15.0)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.1)
charlock_holmes (~> 0.7.5)
......
......@@ -115,6 +115,7 @@ $(() => {
this.state.lists = _.sortBy(this.state.lists, 'position');
Store.addBlankState();
Store.addPromotionState();
this.loading = false;
})
.catch(() => new Flash('An error occurred. Please try again.'));
......
/* eslint-disable comma-dangle, space-before-function-paren, one-var */
/* global Sortable */
import Vue from 'vue';
import boardPromotionState from 'ee/boards/components/board_promotion_state';
import AccessorUtilities from '../../lib/utils/accessor';
import boardList from './board_list';
import boardBlankState from './board_blank_state';
......@@ -17,6 +18,7 @@ gl.issueBoards.Board = Vue.extend({
boardList,
'board-delete': gl.issueBoards.BoardDelete,
boardBlankState,
boardPromotionState,
},
props: {
list: Object,
......
......@@ -12,7 +12,7 @@ class List {
this.position = obj.position;
this.title = obj.title;
this.type = obj.list_type;
this.preset = ['backlog', 'closed', 'blank'].indexOf(this.type) > -1;
this.preset = ['backlog', 'closed', 'blank', 'promotion'].indexOf(this.type) > -1;
this.isExpandable = ['backlog', 'closed'].indexOf(this.type) > -1;
this.isExpanded = true;
this.page = 1;
......@@ -26,7 +26,7 @@ class List {
this.label = new ListLabel(obj.label);
}
if (this.type !== 'blank' && this.id) {
if (this.type !== 'blank' && this.type !== 'promotion' && this.id) {
this.getIssues().catch(() => {
// TODO: handle request error
});
......
......@@ -2,6 +2,7 @@
/* global List */
import _ from 'underscore';
import Cookies from 'js-cookie';
import boardsStoreEE from 'ee/boards/stores/boards_store_ee';
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
......@@ -140,3 +141,5 @@ gl.issueBoards.BoardsStore = {
}
},
};
boardsStoreEE.initEESpecific(gl.issueBoards.BoardsStore);
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');
});
}
};
......@@ -45,7 +45,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';
......@@ -531,6 +530,7 @@ import initGroupAnalytics from './init_group_analytics';
break;
case 'search:show':
new Search();
new UserCallout();
break;
case 'projects:mirrors:show':
case 'projects:mirrors:update':
......@@ -549,6 +549,8 @@ import initGroupAnalytics from './init_group_analytics';
initSettingsPanels();
break;
case 'projects:settings:ci_cd:show':
// Initialize expandable settings panels
initSettingsPanels();
case 'groups:settings:ci_cd:show':
new gl.ProjectVariables();
break;
......@@ -635,9 +637,6 @@ import initGroupAnalytics from './init_group_analytics';
case 'root':
new UserCallout();
break;
case 'groups':
new GroupName();
break;
case 'profiles':
new NotificationsForm();
new NotificationsDropdown();
......@@ -645,7 +644,6 @@ import initGroupAnalytics from './init_group_analytics';
case 'projects':
new Project();
new ProjectAvatar();
new GroupName();
switch (path[1]) {
case 'compare':
new CompareAutocomplete();
......
......@@ -21,8 +21,10 @@ let headerHeight = 50;
export const getHeaderHeight = () => headerHeight;
export const isSidebarCollapsed = () => sidebar && sidebar.classList.contains('sidebar-icons-only');
export const canShowActiveSubItems = (el) => {
if (el.classList.contains('active') && (sidebar && !sidebar.classList.contains('sidebar-icons-only'))) {
if (el.classList.contains('active') && !isSidebarCollapsed()) {
return false;
}
......@@ -100,12 +102,13 @@ export const moveSubItemsToPosition = (el, subItems) => {
export const showSubLevelItems = (el) => {
const subItems = el.querySelector('.sidebar-sub-level-items');
const isIconOnly = subItems && subItems.classList.contains('is-fly-out-only');
if (!canShowSubItems() || !canShowActiveSubItems(el)) return;
el.classList.add(IS_OVER_CLASS);
if (!subItems) return;
if (!subItems || (!isSidebarCollapsed() && isIconOnly)) return;
subItems.style.display = 'block';
el.classList.add(IS_SHOWING_FLY_OUT_CLASS);
......
......@@ -175,7 +175,7 @@ GitLabDropdownFilter = (function() {
elements.show().removeClass('option-hidden');
}
elements.parent().find('.dropdown-menu-empty-link').toggleClass('hidden', elements.is(':visible'));
elements.parent().find('.dropdown-menu-empty-item').toggleClass('hidden', elements.is(':visible'));
}
};
......@@ -247,7 +247,7 @@ GitLabDropdown = (function() {
currentIndex = -1;
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link';
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
SELECTABLE_CLASSES = ".dropdown-content li:not(" + NON_SELECTABLE_CLASSES + ", .option-hidden)";
......@@ -718,7 +718,7 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.noResults = function() {
var html;
return html = '<li class="dropdown-menu-empty-link"><a href="#" class="is-focused">No matching results</a></li>';
return '<li class="dropdown-menu-empty-item"><a>No matching results</a></li>';
};
GitLabDropdown.prototype.rowClicked = function(el) {
......
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');
}
}
......@@ -73,7 +73,7 @@ class Issue {
$(document).trigger('issuable:change', isClosed);
this.toggleCloseReopenButton(isClosed);
let numProjectIssues = Number(projectIssuesCounter.text().replace(/[^\d]/, ''));
let numProjectIssues = Number(projectIssuesCounter.first().text().trim().replace(/[^\d]/, ''));
numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues));
......
......@@ -143,6 +143,7 @@ import './smart_interval';
import './star';
import './subscription';
import './subscription_select';
import initBreadcrumbs from './breadcrumb';
// EE-only scripts
import './admin_email_select';
......@@ -189,6 +190,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 || '/';
......
......@@ -363,7 +363,7 @@
restoreMenu() {
var html;
html = "<ul> <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> </ul>";
html = '<ul><li class="dropdown-menu-empty-item"><a>Loading...</a></li></ul>';
return this.dropdownContent.html(html);
}
......
......@@ -163,12 +163,6 @@
}
}
&.dropdown-menu-empty-link {
&.is-focused {
background-color: $dropdown-empty-row-bg;
}
}
&.dropdown-menu-user-link {
line-height: 16px;
}
......@@ -256,6 +250,13 @@
@include dropdown-link;
}
.dropdown-menu-empty-item a {
&:hover,
&:focus {
background-color: transparent;
}
}
.dropdown-header {
color: $gl-text-color-secondary;
font-size: 13px;
......@@ -800,6 +801,13 @@
}
}
}
&.dropdown-menu-empty-item a {
&:hover,
&:focus {
background-color: transparent;
}
}
}
&.dropdown-menu-selectable {
......@@ -829,4 +837,5 @@
}
}
@include new-style-dropdown('.breadcrumbs-list .dropdown ');
@include new-style-dropdown('.js-namespace-select + ');
@import "framework/variables";
@import 'framework/tw_bootstrap_variables';
@import "bootstrap/variables";
@import "framework/mixins";
header.navbar-gitlab-new {
color: $white-light;
......@@ -301,109 +302,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;
}
}
}
.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;
......@@ -412,49 +342,54 @@ header.navbar-gitlab-new {
}
}
.breadcrumbs-extra {
.breadcrumbs-list {
display: -webkit-flex;
display: flex;
flex: 0 0 auto;
margin-left: auto;
}
.breadcrumbs-sub-title {
margin: 2px 0;
font-size: 16px;
font-weight: $gl-font-weight-normal;
line-height: 1;
ul {
margin: 0;
}
flex-wrap: wrap;
margin-bottom: 0;
line-height: 16px;
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;
}
}
}
a {
color: $gl-text-color;
}
.breadcrumb-item-text {
@include str-truncated(128px);
}
.top-area {
.nav-controls-new-nav {
.dropdown {
@media (min-width: $screen-sm-min) {
margin-right: 0;
}
}
.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;
}
}
......@@ -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;
......@@ -107,11 +106,8 @@ $new-sidebar-collapsed-width: 50px;
overflow-x: hidden;
}
.badge,
.sidebar-context-title {
display: none;
}
.badge:not(.fly-out-badge),
.sidebar-context-title,
.nav-item-name {
display: none;
}
......@@ -119,6 +115,10 @@ $new-sidebar-collapsed-width: 50px;
.sidebar-top-level-items > li > a {
min-height: 44px;
}
.fly-out-top-item {
display: block;
}
}
&.nav-sidebar-expanded {
......@@ -180,6 +180,10 @@ $new-sidebar-collapsed-width: 50px;
width: 16px;
}
}
.fly-out-top-item {
display: none;
}
}
.nav-sidebar-inner-scroll {
......@@ -250,7 +254,7 @@ $new-sidebar-collapsed-width: 50px;
left: $new-sidebar-width;
min-width: 150px;
margin-top: -1px;
padding: 8px 1px;
padding: 4px 1px;
background-color: $white-light;
box-shadow: 2px 1px 3px $dropdown-shadow-color;
border: 1px solid $gray-darker;
......@@ -271,6 +275,13 @@ $new-sidebar-collapsed-width: 50px;
margin-top: 1px;
}
.divider {
height: 1px;
margin: 4px -1px;
padding: 0;
background-color: $dropdown-divider-color;
}
> .active {
box-shadow: none;
......@@ -310,7 +321,7 @@ $new-sidebar-collapsed-width: 50px;
font-weight: $gl-font-weight-bold;
}
.sidebar-sub-level-items {
.sidebar-sub-level-items:not(.is-fly-out-only) {
display: block;
}
}
......@@ -404,6 +415,19 @@ $new-sidebar-collapsed-width: 50px;
}
}
.fly-out-top-item {
> a {
display: flex;
}
.fly-out-badge {
margin-left: 8px;
}
}
.fly-out-top-item-name {
flex: 1;
}
// Mobile nav
......
......@@ -227,12 +227,20 @@
}
}
.board-blank-state {
.board-blank-state,
.board-promotion-state {
height: calc(100% - 49px);
padding: $gl-padding;
background-color: $white-light;
}
.board-promotion-state {
.btn.btn-primary {
display: block;
margin-bottom: 15px;
}
}
.board-blank-state-list {
list-style: none;
......
......@@ -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);
}
......
......@@ -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;
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
*/
......
......@@ -46,6 +46,30 @@
margin-top: 56px;
}
.user-callout.promotion-callout.promotion-advanced-search {
margin: 0;
border-bottom: solid 1px $border-color;
h5 {
margin-top: 0;
}
.bordered-box.content-block {
border: none;
padding: 20px 0;
justify-content: left;
svg {
height: auto;
}
}
.user-callout-copy {
margin-left: 0;
}
}
.promotion-modal {
.modal-dialog {
......@@ -76,3 +100,65 @@
max-width: 700px;
}
}
.promotion-info-weight-message {
padding: $gl-padding-top;
.dropdown-title {
margin: 0 0 10px;
}
.btn {
padding: $gl-vert-padding $gl-btn-padding;
border-radius: $border-radius-default;
display: block;
line-height: $line-height-base;
}
.btn-link {
display: inline;
color: $gl-link-color;
background-color: transparent;
padding: 0;
&:hover {
background-color: transparent;
color: $gl-link-hover-color;
}
}
}
.promotion-issue-template-message {
padding: $gl-padding 30px 20px $gl-padding;
p {
margin-right: 20px;
}
.dropdown-title {
margin: 0 -25px;
padding: 0;
overflow: initial;
border-bottom: none;
}
.btn {
padding: $gl-vert-padding $gl-btn-padding;
border-radius: $border-radius-default;
display: inline-block;
line-height: $line-height-base;
}
.btn-link {
display: inline;
color: $gl-link-color;
padding: 0;
&:hover {
background-color: transparent;
color: $gl-link-hover-color;
}
}
}
class Admin::LogsController < Admin::ApplicationController
prepend EE::Admin::LogsController
before_action :loggers
def show
@loggers = [
end
private
def loggers
@loggers ||= [
Gitlab::AppLogger,
Gitlab::GitLogger,
Gitlab::EnvironmentLogger,
......
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
# This controller's role is to mimic and rewire the Gitlab OAuth
# flow routes for Jira DVCS integration.
# See https://gitlab.com/gitlab-org/gitlab-ee/issues/2381
#
class Oauth::Jira::AuthorizationsController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
# 1. Rewire Jira OAuth initial request to our stablished OAuth authorization URL.
def new
session[:redirect_uri] = params['redirect_uri']
redirect_to oauth_authorization_path(client_id: params['client_id'],
response_type: 'code',
redirect_uri: oauth_jira_callback_url)
end
# 2. Handle the callback call as we were a Github Enterprise instance client.
def callback
# Handling URI query params concatenation.
redirect_uri = URI.parse(session['redirect_uri'])
new_query = URI.decode_www_form(String(redirect_uri.query)) << ['code', params[:code]]
redirect_uri.query = URI.encode_www_form(new_query)
redirect_to redirect_uri.to_s
end
# 3. Rewire and adjust access_token request accordingly.
def access_token
auth_params = params
.slice(:code, :client_id, :client_secret)
.merge(grant_type: 'authorization_code', redirect_uri: oauth_jira_callback_url)
auth_response = HTTParty.post(oauth_token_url, body: auth_params)
token_type, scope, token = auth_response['token_type'], auth_response['scope'], auth_response['access_token']
render text: "access_token=#{token}&scope=#{scope}&token_type=#{token_type}"
end
end
......@@ -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
......
......@@ -89,7 +89,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
......
......@@ -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
......@@ -63,12 +63,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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......@@ -15,19 +15,21 @@ 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")
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
content_tag :span, class: 'group-title' do
full_title.html_safe
end
end
def projects_lfs_status(group)
lfs_status =
......@@ -71,11 +73,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
......
......@@ -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)
......@@ -180,6 +178,13 @@ module IssuablesHelper
end
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
......
......@@ -91,5 +91,9 @@ module LicenseHelper
!@project.feature_available?(project_feature) && show_promotions? && (callout_id.nil? || show_callout?(callout_id))
end
def show_advanced_search_promotion?
!current_application_settings.should_check_namespace_plan? && show_promotions? && show_callout?('promote_advanced_search_dismissed') && !License.feature_available?(:elastic_search)
end
extend self
end
......@@ -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)
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......@@ -338,4 +338,11 @@ module Issuable
metrics = self.metrics || create_metrics
metrics.record!
end
##
# Override in issuable specialization
#
def first_contribution?
false
end
end
......@@ -2,6 +2,10 @@ module Geo
class EventLog < ActiveRecord::Base
include Geo::Model
belongs_to :repository_created_event,
class_name: 'Geo::RepositoryCreatedEvent',
foreign_key: :repository_created_event_id
belongs_to :repository_updated_event,
class_name: 'Geo::RepositoryUpdatedEvent',
foreign_key: :repository_updated_event_id
......@@ -19,6 +23,7 @@ module Geo
foreign_key: :repositories_changed_event_id
def event
repository_created_event ||
repository_updated_event ||
repository_deleted_event ||
repository_renamed_event ||
......
module Geo
class RepositoryCreatedEvent < ActiveRecord::Base
include Geo::Model
belongs_to :project
validates :project, :project_name, :repo_path, :repository_storage_name,
:repository_storage_path, presence: true
end
end
......@@ -20,6 +20,7 @@ class License < ActiveRecord::Base
ISSUE_BOARD_MILESTONE_FEATURE = 'GitLab_IssueBoardMilestone'.freeze
ISSUE_WEIGHTS_FEATURE = 'GitLab_IssueWeights'.freeze
JENKINS_INTEGRATION_FEATURE = 'GitLab_JenkinsIntegration'.freeze
JIRA_DEV_PANEL_INTEGRATION_FEATURE = 'GitLab_JiraDevelopmentPanelIntegration'.freeze
LDAP_EXTRAS_FEATURE = 'GitLab_LdapExtras'.freeze
MERGE_REQUEST_APPROVERS_FEATURE = 'GitLab_MergeRequestApprovers'.freeze
MERGE_REQUEST_REBASE_FEATURE = 'GitLab_MergeRequestRebase'.freeze
......@@ -63,6 +64,7 @@ class License < ActiveRecord::Base
issue_board_milestone: ISSUE_BOARD_MILESTONE_FEATURE,
issue_weights: ISSUE_WEIGHTS_FEATURE,
jenkins_integration: JENKINS_INTEGRATION_FEATURE,
jira_dev_panel_integration: JIRA_DEV_PANEL_INTEGRATION_FEATURE,
merge_request_approvers: MERGE_REQUEST_APPROVERS_FEATURE,
merge_request_rebase: MERGE_REQUEST_REBASE_FEATURE,
merge_request_squash: MERGE_REQUEST_SQUASH_FEATURE,
......@@ -114,6 +116,7 @@ class License < ActiveRecord::Base
{ FILE_LOCKS_FEATURE => 1 },
{ GEO_FEATURE => 1 },
{ OBJECT_STORAGE_FEATURE => 1 },
{ JIRA_DEV_PANEL_INTEGRATION_FEATURE => 1 },
{ SERVICE_DESK_FEATURE => 1 },
{ VARIABLE_ENVIRONMENT_SCOPE_FEATURE => 1 }
].freeze
......
......@@ -983,6 +983,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
......
......@@ -16,6 +16,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
......@@ -33,9 +43,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
......@@ -143,6 +156,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 searchable?
......@@ -212,6 +229,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
......
......@@ -152,7 +152,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.
......
module Geo
class RepositoryCreatedEventStore < EventStore
self.event_type = :repository_created_event
private
def build_event
Geo::RepositoryCreatedEvent.new(
project: project,
repository_storage_name: project.repository.storage,
repository_storage_path: project.repository_storage_path,
repo_path: project.disk_path,
wiki_path: "#{project.disk_path}.wiki",
project_name: project.name
)
end
end
end
- add_to_breadcrumbs "Applications", admin_applications_path
- breadcrumb_title @application.name
- page_title "Edit", @application.name, "Applications"
%h3.page-title Edit application
......
- breadcrumb_title "Cohorts"
- @no_container = true
= render "admin/dashboard/head"
......
- @no_container = true
- breadcrumb_title "Dashboard"
= render "admin/dashboard/head"
%div{ class: container_class }
......
- add_to_breadcrumbs "Groups", admin_groups_path
- breadcrumb_title @group.name
- page_title @group.name, "Groups"
%h3.page-title
Group: #{@group.full_name}
......
- add_to_breadcrumbs "System Hooks", admin_hooks_path
- page_title 'Edit System Hook'
%h3.page-title
Edit System Hook
......
- breadcrumb_title "Jobs"
- @no_container = true
= render "admin/dashboard/head"
......
- add_to_breadcrumbs "Labels", admin_labels_path
- breadcrumb_title "Edit Label"
- page_title "Edit", @label.name, "Labels"
%h3.page-title
Edit Label
......
- 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}
......
- breadcrumb_title "Runners"
- @no_container = true
= render "admin/dashboard/head"
......
- add_to_breadcrumbs "Service Templates", admin_application_settings_services_path
- breadcrumb_title @service.title
- page_title @service.title, "Service Templates"
= render 'form'
- add_to_breadcrumbs "Users", admin_users_path
- breadcrumb_title @user.name
- page_title @user.name, "Users"
= render 'admin/users/head'
......
%h4.prepend-top-0
Secret variables
= link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'secret-variables'), target: '_blank'
- if @variable.respond_to?(:environment_scope) && @project.feature_available?(:variable_environment_scope)
%p
These variables will be set to environment by the runner, and could be protected by exposing only to protected branches or tags, or some particular environments.
- else
%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.
.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"
......
......@@ -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"
- if current_user.can_create_group?
- content_for :breadcrumbs_extra do
= link_to "New group", new_group_path, class: "btn btn-new"
.top-area
%ul.nav-links
= nav_link(page: dashboard_groups_path) do
......@@ -10,8 +6,8 @@
= nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore public groups' do
Explore public groups
.nav-controls.nav-controls-new-nav
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
= link_to "New group", new_group_path, class: "btn btn-new visible-xs"
= link_to "New group", new_group_path, class: "btn btn-new"
= content_for :flash_message do
= render 'shared/project_limit'
- if current_user.can_create_project?
- content_for :breadcrumbs_extra do
= link_to "New project", new_project_path, class: 'btn btn-new'
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
......@@ -19,8 +15,8 @@
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore projects
.nav-controls.nav-controls-new-nav
.nav-controls
= render 'shared/projects/search_form'
= render 'shared/projects/dropdown'
- if current_user.can_create_project?
= link_to "New project", new_project_path, class: "btn btn-new visible-xs"
= link_to "New project", new_project_path, class: "btn btn-new"
- if current_user
- content_for :breadcrumbs_extra do
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
.top-area
%ul.nav-links
= nav_link(page: dashboard_snippets_path, html_options: {class: 'home'}) do
......@@ -10,3 +6,7 @@
= nav_link(page: explore_snippets_path) do
= link_to explore_snippets_path, title: 'Explore snippets', data: {placement: 'right'} do
Explore Snippets
- if current_user
.nav-controls.hidden-xs
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
......@@ -4,14 +4,9 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls.visible-xs
.nav-controls
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
......
......@@ -2,12 +2,9 @@
- page_title "Merge Requests"
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
.top-area
= render 'shared/issuable/nav', type: :merge_requests
.nav-controls.visible-xs
.nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
= render 'shared/issuable/filter', type: :merge_requests
......
......@@ -2,13 +2,10 @@
- page_title 'Milestones'
- header_title 'Milestones', dashboard_milestones_path
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls.visible-xs
.nav-controls
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.milestones
......
- breadcrumb_title "General Settings"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
.panel-heading
......
......@@ -9,18 +9,10 @@
= webpack_bundle_tag 'filtered_search'
= webpack_bundle_tag 'issues'
- if group_issues_exists
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10' do
= icon('rss')
%span.icon-label
Subscribe
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues
- if group_issues_exists
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls.visible-xs
.nav-controls
= link_to params.merge(rss_url_options), class: 'btn' do
= icon('rss')
%span.icon-label
......
- page_title 'Labels'
- if can?(current_user, :admin_label, @group)
- content_for :breadcrumbs_extra do
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
= render "groups/head_issues"
......@@ -10,7 +7,7 @@
.nav-text
Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
.nav-controls.visible-xs
.nav-controls
- if can?(current_user, :admin_label, @group)
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
......
......@@ -4,17 +4,13 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
- if current_user
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
- if @group_merge_requests.empty?
= render 'shared/empty_states/merge_requests', project_select_button: true
- else
.top-area
= render 'shared/issuable/nav', type: :merge_requests
- if current_user
.nav-controls.visible-xs
.nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
= render 'shared/issuable/search_bar', type: :merge_requests
......
- page_title "Milestones"
- if can?(current_user, :admin_milestones, @group)
- content_for :breadcrumbs_extra do
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
= render "groups/head_issues"
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls.visible-xs
.nav-controls
- if can?(current_user, :admin_milestones, @group)
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
......
- breadcrumb_title "Projects"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default
......
- page_title "Pipelines"
- breadcrumb_title "CI / CD Settings"
- page_title "CI / CD"
= render "groups/settings_head"
= render 'ci/variables/index'
- @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")
......
- breadcrumb_title "Details"
- @no_container = true
= render 'head'
......
......@@ -17,8 +17,8 @@
.dropdown-menu.dropdown-select
= dropdown_content do
%ul
%li
%a.is-focused.dropdown-menu-empty-link
%li.dropdown-menu-empty-item
%a
Loading...
= dropdown_loading
%i.search-icon
......
- breadcrumb_link = breadcrumb_title_link
- container = @no_breadcrumb_container ? 'container-fluid' : container_class
- hide_top_links = @hide_top_links || false
%nav.breadcrumbs{ role: "navigation" }
.breadcrumbs-container{ class: [container, @content_class] }
%nav.breadcrumbs{ role: "navigation", class: [container, @content_class] }
.breadcrumbs-container
- 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
%ul.list-unstyled.breadcrumbs-list.js-breadcrumbs-list
- unless hide_top_links
.title
= link_to "GitLab", root_path
\/
- if content_for?(:header_title_before)
= yield :header_title_before
\/
= 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 content_for?(:breadcrumbs_extra)
.breadcrumbs-extra.hidden-xs= yield :breadcrumbs_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
= yield :header_content
- 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
......@@ -14,6 +14,11 @@
Overview
%ul.sidebar-sub-level-items
= nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts), html_options: { class: "fly-out-top-item" } ) do
= link_to admin_root_path do
%strong.fly-out-top-item-name
#{ _('Overview') }
%li.divider.fly-out-top-item
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview' do
%span
......@@ -55,6 +60,11 @@
Monitoring
%ul.sidebar-sub-level-items
= nav_link(controller: %w(conversational_development_index system_info background_jobs logs health_check requests_profiles), html_options: { class: "fly-out-top-item" } ) do
= link_to admin_conversational_development_index_path do
%strong.fly-out-top-item-name
#{ _('Monitoring') }
%li.divider.fly-out-top-item
= nav_link(controller: :system_info) do
= link_to admin_system_info_path, title: 'System Info' do
%span
......@@ -83,6 +93,11 @@
= custom_icon('messages')
%span.nav-item-name
Messages
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :broadcast_messages, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_broadcast_messages_path do
%strong.fly-out-top-item-name
#{ _('Messages') }
= nav_link(controller: [:hooks, :hook_logs]) do
= sidebar_link admin_hooks_path, title: _('Hooks') do
......@@ -90,6 +105,11 @@
= custom_icon('system_hooks')
%span.nav-item-name
System Hooks
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: [:hooks, :hook_logs], html_options: { class: "fly-out-top-item" } ) do
= link_to admin_hooks_path do
%strong.fly-out-top-item-name
#{ _('System Hooks') }
= nav_link(controller: :applications) do
= sidebar_link admin_applications_path, title: _('Applications') do
......@@ -97,6 +117,11 @@
= custom_icon('applications')
%span.nav-item-name
Applications
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :applications, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_applications_path do
%strong.fly-out-top-item-name
#{ _('Applications') }
= nav_link(controller: :abuse_reports) do
= sidebar_link admin_abuse_reports_path, title: _("Abuse Reports") do
......@@ -105,6 +130,12 @@
%span.nav-item-name
Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :abuse_reports, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_broadcast_messages_path do
%strong.fly-out-top-item-name
#{ _('Abuse Reports') }
%span.badge.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(AbuseReport.count(:all))
= nav_link(controller: :licenses) do
= sidebar_link admin_license_path, title: _('License') do
......@@ -112,6 +143,11 @@
= custom_icon('license')
%span.nav-item-name
License
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :licenses, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_license_path do
%strong.fly-out-top-item-name
#{ _('License') }
- if akismet_enabled?
= nav_link(controller: :spam_logs) do
......@@ -120,6 +156,11 @@
= custom_icon('spam_logs')
%span.nav-item-name
Spam Logs
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :spam_logs, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_spam_logs_path do
%strong.fly-out-top-item-name
#{ _('Spam Logs') }
= nav_link(controller: :push_rules) do
= sidebar_link admin_push_rule_path, title: _('Push Rules') do
......@@ -127,6 +168,11 @@
= custom_icon('push_rules')
%span.nav-item-name
Push Rules
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :push_rules, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_push_rule_path do
%strong.fly-out-top-item-name
#{ _('Push Rules') }
= nav_link(controller: :geo_nodes) do
= sidebar_link admin_geo_nodes_path, title: _('Geo Nodes') do
......@@ -134,6 +180,11 @@
= custom_icon('geo_nodes')
%span.nav-item-name
Geo Nodes
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :geo_nodes, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_geo_nodes_path do
%strong.fly-out-top-item-name
#{ _('Geo Nodes') }
= nav_link(controller: :deploy_keys) do
= sidebar_link admin_deploy_keys_path, title: _('Deploy Keys') do
......@@ -141,6 +192,11 @@
= custom_icon('key')
%span.nav-item-name
Deploy Keys
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :deploy_keys, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_deploy_keys_path do
%strong.fly-out-top-item-name
#{ _('Deploy Keys') }
= nav_link(controller: :services) do
= sidebar_link admin_application_settings_services_path, title: _('Service Templates') do
......@@ -148,6 +204,11 @@
= custom_icon('service_templates')
%span.nav-item-name
Service Templates
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :services, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_services_path do
%strong.fly-out-top-item-name
#{ _('Service Templates') }
= nav_link(controller: :labels) do
= sidebar_link admin_labels_path, title: _('Labels') do
......@@ -155,6 +216,11 @@
= custom_icon('labels')
%span.nav-item-name
Labels
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :labels, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_labels_path do
%strong.fly-out-top-item-name
#{ _('Labels') }
= nav_link(controller: :appearances) do
= sidebar_link admin_appearances_path, title: _('Appearances') do
......@@ -162,6 +228,11 @@
= custom_icon('appearance')
%span.nav-item-name
Appearance
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :appearances, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_appearances_path do
%strong.fly-out-top-item-name
#{ _('Appearance') }
= nav_link(controller: :application_settings) do
= sidebar_link admin_application_settings_path, title: _('Settings') do
......@@ -169,5 +240,10 @@
= custom_icon('settings')
%span.nav-item-name
Settings
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_path do
%strong.fly-out-top-item-name
#{ _('Settings') }
= render 'shared/sidebar_toggle_button'
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
.nav-sidebar{ class: ("sidebar-icons-only" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll
.context-header
......@@ -15,6 +18,11 @@
Overview
%ul.sidebar-sub-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do
= link_to group_path(@group) do
%strong.fly-out-top-item-name
#{ _('Overview') }
%li.divider.fly-out-top-item
= nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'Group details' do
%span
......@@ -36,11 +44,16 @@
.nav-icon-container
= custom_icon('issues')
%span.nav-item-name
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
Issues
%span.badge.count= number_with_delimiter(issues.count)
%ul.sidebar-sub-level-items
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index'], html_options: { class: "fly-out-top-item" } ) do
= link_to issues_group_path(@group) do
%strong.fly-out-top-item-name
#{ _('Issues') }
%span.badge.count.issue_counter.fly-out-badge= number_with_delimiter(issues.count)
%li.divider.fly-out-top-item
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
= link_to issues_group_path(@group), title: 'List' do
%span
......@@ -61,15 +74,25 @@
.nav-icon-container
= custom_icon('mr_bold')
%span.nav-item-name
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
Merge Requests
%span.badge.count= number_with_delimiter(merge_requests.count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: 'groups#merge_requests', html_options: { class: "fly-out-top-item" } ) do
= link_to merge_requests_group_path(@group) do
%strong.fly-out-top-item-name
#{ _('Merge Requests') }
%span.badge.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(merge_requests.count)
= nav_link(path: 'group_members#index') do
= sidebar_link group_group_members_path(@group), title: _('Members') do
.nav-icon-container
= custom_icon('members')
%span.nav-item-name
Members
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: 'group_members#index', html_options: { class: "fly-out-top-item" } ) do
= link_to merge_requests_group_path(@group) do
%strong.fly-out-top-item-name
#{ _('Members') }
- if current_user && can?(current_user, :admin_group, @group)
= nav_link(path: %w[groups#projects groups#edit ci_cd#show ldap_group_links#index hooks#index audit_events#index pipeline_quota#index]) do
= sidebar_link edit_group_path(@group), title: _('Settings') do
......@@ -78,6 +101,11 @@
%span.nav-item-name
Settings
%ul.sidebar-sub-level-items
= nav_link(path: %w[groups#projects groups#edit ci_cd#show], html_options: { class: "fly-out-top-item" } ) do
= link_to edit_group_path(@group) do
%strong.fly-out-top-item-name
#{ _('Settings') }
%li.divider.fly-out-top-item
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group), title: 'General' do
%span
......
......@@ -12,12 +12,22 @@
= custom_icon('profile')
%span.nav-item-name
Profile
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: 'profiles#show', html_options: { class: "fly-out-top-item" } ) do
= link_to profile_path do
%strong.fly-out-top-item-name
#{ _('Profile') }
= nav_link(controller: [:accounts, :two_factor_auths]) do
= sidebar_link profile_account_path, title: _('Account') do
.nav-icon-container
= custom_icon('account')
%span.nav-item-name
Account
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: [:accounts, :two_factor_auths], html_options: { class: "fly-out-top-item" } ) do
= link_to profile_account_path do
%strong.fly-out-top-item-name
#{ _('Account') }
- if current_application_settings.should_check_namespace_plan?
= nav_link(controller: :billings) do
= sidebar_link profile_billings_path, title: _('Billing') do
......@@ -25,6 +35,11 @@
= custom_icon('credit_card')
%span.nav-item-name
Billing
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :billings, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_billings_path do
%strong.fly-out-top-item-name
#{ _('Billing') }
- if current_application_settings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do
= sidebar_link applications_profile_path, title: _('Applications') do
......@@ -32,24 +47,44 @@
= custom_icon('applications')
%span.nav-item-name
Applications
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: 'oauth/applications', html_options: { class: "fly-out-top-item" } ) do
= link_to applications_profile_path do
%strong.fly-out-top-item-name
#{ _('Applications') }
= nav_link(controller: :chat_names) do
= sidebar_link profile_chat_names_path, title: _('Chat') do
.nav-icon-container
= custom_icon('chat')
%span.nav-item-name
Chat
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :chat_names, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_chat_names_path do
%strong.fly-out-top-item-name
#{ _('Chat') }
= nav_link(controller: :personal_access_tokens) do
= sidebar_link profile_personal_access_tokens_path, title: _('Access Tokens') do
.nav-icon-container
= custom_icon('access_tokens')
%span.nav-item-name
Access Tokens
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :personal_access_tokens, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_personal_access_tokens_path do
%strong.fly-out-top-item-name
#{ _('Access Tokens') }
= nav_link(controller: :emails) do
= sidebar_link profile_emails_path, title: _('Emails') do
.nav-icon-container
= custom_icon('emails')
%span.nav-item-name
Emails
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :emails, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_emails_path do
%strong.fly-out-top-item-name
#{ _('Emails') }
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= sidebar_link edit_profile_password_path, title: _('Password') do
......@@ -57,41 +92,76 @@
= custom_icon('lock')
%span.nav-item-name
Password
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :passwords, html_options: { class: "fly-out-top-item" } ) do
= link_to edit_profile_password_path do
%strong.fly-out-top-item-name
#{ _('Password') }
= nav_link(controller: :notifications) do
= sidebar_link profile_notifications_path, title: _('Notifications') do
.nav-icon-container
= custom_icon('notifications')
%span.nav-item-name
Notifications
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :notifications, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_notifications_path do
%strong.fly-out-top-item-name
#{ _('Notifications') }
= nav_link(controller: :keys) do
= sidebar_link profile_keys_path, title: _('SSH Keys') do
.nav-icon-container
= custom_icon('key')
%span.nav-item-name
SSH Keys
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :keys, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_keys_path do
%strong.fly-out-top-item-name
#{ _('SSH Keys') }
= nav_link(controller: :gpg_keys) do
= sidebar_link profile_gpg_keys_path, title: _('GPG Keys') do
.nav-icon-container
= custom_icon('key_2')
%span.nav-item-name
GPG Keys
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :gpg_keys, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_gpg_keys_path do
%strong.fly-out-top-item-name
#{ _('GPG Keys') }
= nav_link(controller: :preferences) do
= sidebar_link profile_preferences_path, title: _('Preferences') do
.nav-icon-container
= custom_icon('preferences')
%span.nav-item-name
Preferences
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :preferences, html_options: { class: "fly-out-top-item" } ) do
= link_to profile_preferences_path do
%strong.fly-out-top-item-name
#{ _('Preferences') }
= nav_link(path: 'profiles#audit_log') do
= sidebar_link audit_log_profile_path, title: _('Authentication log') do
.nav-icon-container
= custom_icon('authentication_log')
%span.nav-item-name
Authentication log
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: 'profiles#audit_log', html_options: { class: "fly-out-top-item" } ) do
= link_to audit_log_profile_path do
%strong.fly-out-top-item-name
#{ _('Authentication Log') }
= nav_link(path: 'profiles#pipeline_quota') do
= sidebar_link profile_pipeline_quota_path, title: _('Pipeline quota') do
.nav-icon-container
= custom_icon('pipeline')
%span.nav-item-name
Pipeline quota
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: 'profiles#pipeline_quota', html_options: { class: "fly-out-top-item" } ) do
= link_to profile_pipeline_quota_path do
%strong.fly-out-top-item-name
#{ _('Pipeline quota') }
= render 'shared/sidebar_toggle_button'
......@@ -16,6 +16,11 @@
Overview
%ul.sidebar-sub-level-items
= nav_link(path: 'projects#show', html_options: { class: "fly-out-top-item" } ) do
= link_to project_path(@project) do
%strong.fly-out-top-item-name
#{ _('Overview') }
%li.divider.fly-out-top-item
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: _('Project details'), class: 'shortcuts-project' do
%span= _('Details')
......@@ -38,6 +43,11 @@
Repository
%ul.sidebar-sub-level-items
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare projects/repositories tags branches releases graphs network), html_options: { class: "fly-out-top-item" } ) do
= link_to project_tree_path(@project) do
%strong.fly-out-top-item-name
#{ _('Repository') }
%li.divider.fly-out-top-item
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_tree_path(@project) do
#{ _('Files') }
......@@ -82,6 +92,11 @@
= custom_icon('container_registry')
%span.nav-item-name
Registry
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: %w[projects/registry/repositories], html_options: { class: "fly-out-top-item" } ) do
= link_to project_container_registry_index_path(@project) do
%strong.fly-out-top-item-name
#{ _('Registry') }
- if project_nav_tab? :issues
= nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do
......@@ -95,6 +110,14 @@
= number_with_delimiter(@project.open_issues_count)
%ul.sidebar-sub-level-items
= nav_link(controller: :issues, html_options: { class: "fly-out-top-item" } ) do
= link_to project_issues_path(@project) do
%strong.fly-out-top-item-name
#{ _('Issues') }
- if @project.issues_enabled?
%span.badge.count.issue_counter.fly-out-badge
= number_with_delimiter(@project.open_issues_count)
%li.divider.fly-out-top-item
= nav_link(controller: :issues) do
= link_to project_issues_path(@project), title: 'Issues' do
%span
......@@ -138,6 +161,13 @@
Merge Requests
%span.badge.count.merge_counter.js-merge-counter
= number_with_delimiter(@project.open_merge_requests_count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :merge_requests, html_options: { class: "fly-out-top-item" } ) do
= link_to project_merge_requests_path(@project) do
%strong.fly-out-top-item-name
#{ _('Merge Requests') }
%span.badge.count.merge_counter.js-merge-counter.fly-out-badge
= number_with_delimiter(@project.open_merge_requests_count)
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :environments, :artifacts]) do
......@@ -148,6 +178,11 @@
CI / CD
%ul.sidebar-sub-level-items
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :environments, :artifacts], html_options: { class: "fly-out-top-item" } ) do
= link_to project_pipelines_path(@project) do
%strong.fly-out-top-item-name
#{ _('CI / CD') }
%li.divider.fly-out-top-item
- if project_nav_tab? :pipelines
= nav_link(path: ['pipelines#index', 'pipelines#show']) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
......@@ -185,6 +220,11 @@
= custom_icon('wiki')
%span.nav-item-name
Wiki
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :wikis, html_options: { class: "fly-out-top-item" } ) do
= link_to get_project_wiki_path(@project) do
%strong.fly-out-top-item-name
#{ _('Wiki') }
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
......@@ -193,6 +233,11 @@
= custom_icon('snippets')
%span.nav-item-name
Snippets
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :snippets, html_options: { class: "fly-out-top-item" } ) do
= link_to project_snippets_path(@project) do
%strong.fly-out-top-item-name
#{ _('Snippets') }
- if project_nav_tab? :settings
= nav_link(path: %w[projects#edit project_members#index integrations#show services#edit repository#show ci_cd#show pages#show]) do
......@@ -205,6 +250,11 @@
%ul.sidebar-sub-level-items
- can_edit = can?(current_user, :admin_project, @project)
- if can_edit
= nav_link(path: %w[projects#edit project_members#index integrations#show services#edit repository#show ci_cd#show pages#show], html_options: { class: "fly-out-top-item" } ) do
= link_to edit_project_path(@project) do
%strong.fly-out-top-item-name
#{ _('Settings') }
%li.divider.fly-out-top-item
= nav_link(path: %w[projects#edit]) do
= link_to edit_project_path(@project), title: 'General' do
%span
......
- breadcrumb_title "Edit Password"
- page_title "Password"
- @content_class = "limit-container-width" unless fluid_layout
......
- breadcrumb_title "Access Tokens"
- page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout
......
- breadcrumb_title "Profile"
- breadcrumb_title "Edit Profile"
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
......
- @no_container = true
- add_to_breadcrumbs(_("Project"), project_path(@project))
- page_title _("Activity")
= render "projects/head"
= render 'projects/last_push'
......
- 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
......
......@@ -2,8 +2,8 @@
- @no_breadcrumb_container = true
- @no_container = true
- @content_class = "issue-boards-content js-focus-mode-board"
- breadcrumb_title "Issue Boards"
- page_title "Boards"
- add_to_breadcrumbs("Issues", project_issues_path(@project))
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'
......@@ -12,6 +12,7 @@
%script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board"
%script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal
%script#js-board-promotion{ type: "text/x-template" }= render "shared/promotions/promote_issue_board"
= render "projects/issues/head"
......
......@@ -17,7 +17,7 @@
class: "label color-label title",
":style" => "{ backgroundColor: (list.label && list.label.color ? list.label.color : null), color: (list.label && list.label.color ? list.label.text_color : \"#2e2e2e\") }" }
{{ list.title }}
.issue-count-badge.pull-right.clearfix{ "v-if" => 'list.type !== "blank"' }
.issue-count-badge.pull-right.clearfix{ "v-if" => 'list.type !== "blank" && list.type !== "promotion"' }
%span.issue-count-badge-count.pull-left{ ":class" => '{ "has-btn": list.type !== "closed" && !disabled }' }
{{ list.issuesSize }}
- if can?(current_user, :admin_issue, @project)
......@@ -34,7 +34,7 @@
"v-if" => "!list.preset && list.id" }
%button.board-delete.has-tooltip.pull-right{ type: "button", title: "Delete list", "aria-label" => "Delete list", data: { placement: "bottom" }, "@click.stop" => "deleteBoard" }
= icon("trash")
%board-list{ "v-if" => 'list.type !== "blank"',
%board-list{ "v-if" => 'list.type !== "blank" && list.type !== "promotion"',
":list" => "list",
":issues" => "list.issues",
":loading" => "list.loading",
......@@ -44,3 +44,4 @@
"ref" => "board-list" }
- if can?(current_user, :admin_list, @project)
%board-blank-state{ "v-if" => 'list.id == "blank"' }
%board-promotion-state{ "v-if" => 'list.id == "promotion"' }
- @no_container = true
- page_title "Branches"
- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class }
......
- @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
......
......@@ -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"
......
- @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 }
......
- @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 }
......
- @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')
......
......@@ -29,6 +29,6 @@
+#{diff_file.added_lines}
%span.cred<
\-#{diff_file.removed_lines}
%li.dropdown-menu-empty-link.hidden
%a{ href: "#" }
%li.dropdown-menu-empty-item.hidden
%a
No files found.
- breadcrumb_title "General Settings"
- page_title "General"
- @content_class = "limit-container-width" unless fluid_layout
- expanded = Rails.env.test?
......
- @no_container = true
- breadcrumb_title "Details"
= render partial: 'flash_messages', locals: { project: @project }
......
- @no_container = true
- add_to_breadcrumbs "Environments", project_environments_path(@project)
- breadcrumb_title @environment.name
- page_title "Environments"
= render "projects/pipelines/head"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment