summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js10
-rw-r--r--app/assets/javascripts/filtered_search/stores/recent_searches_store.js1
-rw-r--r--app/assets/javascripts/issue_show/services/index.js6
-rw-r--r--app/assets/javascripts/notes.js8
-rw-r--r--app/assets/stylesheets/framework/nav.scss22
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss1
-rw-r--r--app/assets/stylesheets/pages/builds.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss12
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss23
-rw-r--r--app/assets/stylesheets/pages/notes.scss9
-rw-r--r--app/controllers/projects/issues_controller.rb6
-rw-r--r--[-rwxr-xr-x]app/controllers/projects/merge_requests_controller.rb0
-rw-r--r--app/finders/users_finder.rb74
-rw-r--r--app/helpers/submodule_helper.rb4
-rw-r--r--app/models/issue.rb2
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/views/projects/builds/_sidebar.html.haml2
-rw-r--r--app/views/projects/merge_requests/_show.html.haml70
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml2
19 files changed, 180 insertions, 76 deletions
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 9fea563370f..57d247e11a9 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -16,10 +16,14 @@ class FilteredSearchManager {
this.recentSearchesStore = new RecentSearchesStore({
isLocalStorageAvailable: RecentSearchesService.isAvailable(),
});
- let recentSearchesKey = 'issue-recent-searches';
+ const searchHistoryDropdownElement = document.querySelector('.js-filtered-search-history-dropdown');
+ const projectPath = searchHistoryDropdownElement ?
+ searchHistoryDropdownElement.dataset.projectFullPath : 'project';
+ let recentSearchesPagePrefix = 'issue-recent-searches';
if (page === 'merge_requests') {
- recentSearchesKey = 'merge-request-recent-searches';
+ recentSearchesPagePrefix = 'merge-request-recent-searches';
}
+ const recentSearchesKey = `${projectPath}-${recentSearchesPagePrefix}`;
this.recentSearchesService = new RecentSearchesService(recentSearchesKey);
// Fetch recent searches from localStorage
@@ -47,7 +51,7 @@ class FilteredSearchManager {
this.recentSearchesRoot = new RecentSearchesRoot(
this.recentSearchesStore,
this.recentSearchesService,
- document.querySelector('.js-filtered-search-history-dropdown'),
+ searchHistoryDropdownElement,
);
this.recentSearchesRoot.init();
diff --git a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
index 066be69766a..35fc15e4c87 100644
--- a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
+++ b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
@@ -3,6 +3,7 @@ import _ from 'underscore';
class RecentSearchesStore {
constructor(initialState = {}) {
this.state = Object.assign({
+ isLocalStorageAvailable: true,
recentSearches: [],
}, initialState);
}
diff --git a/app/assets/javascripts/issue_show/services/index.js b/app/assets/javascripts/issue_show/services/index.js
index 5da15882c25..0ceff34cf8b 100644
--- a/app/assets/javascripts/issue_show/services/index.js
+++ b/app/assets/javascripts/issue_show/services/index.js
@@ -8,15 +8,15 @@ export default class Service {
this.endpoint = endpoint;
this.resource = Vue.resource(this.endpoint, {}, {
- rendered_title: {
+ realtimeChanges: {
method: 'GET',
- url: `${this.endpoint}/rendered_title`,
+ url: `${this.endpoint}/realtime_changes`,
},
});
}
getData() {
- return this.resource.rendered_title();
+ return this.resource.realtimeChanges();
}
deleteIssuable() {
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 7ba44835741..f143bfbfc29 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -24,7 +24,7 @@ const normalizeNewlines = function(str) {
(function() {
this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
- const REGEX_SLASH_COMMANDS = /^\/\w+/gm;
+ const REGEX_SLASH_COMMANDS = /^\/\w+.*$/gm;
Notes.interval = null;
@@ -1170,6 +1170,7 @@ const normalizeNewlines = function(str) {
*/
Notes.prototype.createPlaceholderNote = function({ formContent, uniqueId, isDiscussionNote, currentUsername, currentUserFullname }) {
const discussionClass = isDiscussionNote ? 'discussion' : '';
+ const escapedFormContent = _.escape(formContent);
const $tempNote = $(
`<li id="${uniqueId}" class="note being-posted fade-in-half timeline-entry">
<div class="timeline-entry-inner">
@@ -1183,14 +1184,11 @@ const normalizeNewlines = function(str) {
<span class="hidden-xs">${currentUserFullname}</span>
<span class="note-headline-light">@${currentUsername}</span>
</a>
- <span class="note-headline-light">
- <i class="fa fa-spinner fa-spin" aria-label="Comment is being posted" aria-hidden="true"></i>
- </span>
</div>
</div>
<div class="note-body">
<div class="note-text">
- <p>${formContent}</p>
+ <p>${escapedFormContent}</p>
</div>
</div>
</div>
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 64e6ab391b6..d2f6a227128 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -24,10 +24,10 @@
}
@mixin scrolling-links() {
- white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
+ display: flex;
&::-webkit-scrollbar {
display: none;
@@ -35,6 +35,7 @@
}
.nav-links {
+ display: flex;
padding: 0;
margin: 0;
list-style: none;
@@ -42,17 +43,16 @@
border-bottom: 1px solid $border-color;
li {
- display: inline-block;
+ display: flex;
a {
- display: inline-block;
padding: $gl-btn-padding;
padding-bottom: 11px;
- margin-bottom: -1px;
font-size: 14px;
line-height: 28px;
color: $gl-text-color-secondary;
border-bottom: 2px solid transparent;
+ white-space: nowrap;
&:hover,
&:active,
@@ -85,10 +85,10 @@
.container-fluid {
background-color: $gray-normal;
margin-bottom: 0;
+ display: flex;
}
li {
-
&.active a {
border-bottom: none;
color: $link-underline-blue;
@@ -137,9 +137,9 @@
}
.nav-links {
- display: inline-block;
margin-bottom: 0;
border-bottom: none;
+ float: left;
&.wide {
width: 100%;
@@ -337,6 +337,10 @@
border-bottom: none;
height: 51px;
+ @media (min-width: $screen-sm-min) {
+ justify-content: center;
+ }
+
li {
a {
padding-top: 10px;
@@ -347,6 +351,7 @@
.scrolling-tabs-container {
position: relative;
+ overflow: hidden;
.nav-links {
@include scrolling-links();
@@ -484,10 +489,7 @@
.inner-page-scroll-tabs {
position: relative;
-
- .nav-links {
- padding-bottom: 1px;
- }
+ overflow: hidden;
.fade-right {
@include fade(left, $white-light);
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 2b5ab539955..018f61ca3a8 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -53,6 +53,7 @@
.right-sidebar-expanded {
padding-right: 0;
+ z-index: 300;
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
&:not(.wiki-sidebar):not(.build-sidebar) .content-wrapper {
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 724b4080ee0..14a62b6cbf0 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -378,7 +378,7 @@
background-color: $row-hover;
}
- .fa-spinner {
+ .fa-refresh {
font-size: 13px;
margin-left: 3px;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index c4210ffd823..0184208ab82 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -23,16 +23,6 @@
.merge-manually {
@extend .fixed-width-container;
}
-
- .merge-request-tabs-holder {
- &.affix {
- border-bottom: 1px solid $border-color;
-
- .nav-links {
- border: 0;
- }
- }
- }
}
.merge-request-details {
@@ -206,7 +196,7 @@
transition: width .3s;
background: $gray-light;
padding: 10px 20px;
- z-index: 2;
+ z-index: 200;
&.right-sidebar-expanded {
width: $gutter_width;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 0173a05b403..d208e54207e 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -121,6 +121,7 @@
.dropdown-menu {
margin-top: 11px;
+ z-index: 200;
}
.ci-action-icon-wrapper {
@@ -690,8 +691,9 @@
.merge-request-tabs-holder {
top: $header-height;
- z-index: 10;
+ z-index: 100;
background-color: $white-light;
+ border-bottom: 1px solid $border-color;
@media(min-width: $screen-sm-min) {
position: sticky;
@@ -711,6 +713,16 @@
padding-right: $gl-padding;
}
}
+
+ .nav-links {
+ border: 0;
+ }
+}
+
+.merge-request-tabs {
+ display: flex;
+ margin-bottom: 0;
+ padding: 0;
}
.limit-container-width {
@@ -721,6 +733,15 @@
}
}
+.merge-request-tabs-container {
+ display: flex;
+ justify-content: space-between;
+
+ @media (max-width: $screen-xs-max) {
+ flex-direction: column-reverse;
+ }
+}
+
.limit-container-width:not(.container-limited) {
.merge-request-tabs-holder:not(.affix) {
.merge-request-tabs-container {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 0600bb1cb1a..5b6aa9d74f6 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -609,6 +609,15 @@ ul.notes {
}
.line-resolve-all-container {
+ @media (min-width: $screen-sm-min) {
+ margin-right: 0;
+ padding-left: $gl-padding;
+ }
+
+ > div {
+ white-space: nowrap;
+ }
+
.btn-group {
margin-left: -4px;
}
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 760ba246e3e..46438e68d54 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -11,10 +11,10 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
- :related_branches, :can_create_branch, :rendered_title, :create_merge_request]
+ :related_branches, :can_create_branch, :realtime_changes, :create_merge_request]
# Allow read any issue
- before_action :authorize_read_issue!, only: [:show, :rendered_title]
+ before_action :authorize_read_issue!, only: [:show, :realtime_changes]
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
@@ -199,7 +199,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
- def rendered_title
+ def realtime_changes
Gitlab::PollingInterval.set_header(response, interval: 3_000)
render json: {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index b99ccd453b8..b99ccd453b8 100755..100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
diff --git a/app/finders/users_finder.rb b/app/finders/users_finder.rb
new file mode 100644
index 00000000000..dbd50d1db7c
--- /dev/null
+++ b/app/finders/users_finder.rb
@@ -0,0 +1,74 @@
+# UsersFinder
+#
+# Used to filter users by set of params
+#
+# Arguments:
+# current_user - which user use
+# params:
+# username: string
+# extern_uid: string
+# provider: string
+# search: string
+# active: boolean
+# blocked: boolean
+# external: boolean
+#
+class UsersFinder
+ attr_accessor :current_user, :params
+
+ def initialize(current_user, params = {})
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute
+ users = User.all
+ users = by_username(users)
+ users = by_search(users)
+ users = by_blocked(users)
+ users = by_active(users)
+ users = by_external_identity(users)
+ users = by_external(users)
+
+ users
+ end
+
+ private
+
+ def by_username(users)
+ return users unless params[:username]
+
+ users.where(username: params[:username])
+ end
+
+ def by_search(users)
+ return users unless params[:search].present?
+
+ users.search(params[:search])
+ end
+
+ def by_blocked(users)
+ return users unless params[:blocked]
+
+ users.blocked
+ end
+
+ def by_active(users)
+ return users unless params[:active]
+
+ users.active
+ end
+
+ def by_external_identity(users)
+ return users unless current_user.admin? && params[:extern_uid] && params[:provider]
+
+ users.joins(:identities).merge(Identity.with_extern_uid(params[:provider], params[:extern_uid]))
+ end
+
+ def by_external(users)
+ return users = users.where.not(external: true) unless current_user.admin?
+ return users unless params[:external]
+
+ users.external
+ end
+end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index b739554a7a4..09b73eee8cf 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -7,6 +7,10 @@ module SubmoduleHelper
def submodule_links(submodule_item, ref = nil, repository = @repository)
url = repository.submodule_url_for(ref, submodule_item.path)
+ if url == '.' || url == './'
+ url = File.join(Gitlab.config.gitlab.url, @project.full_path)
+ end
+
if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace, project = $1, $2
project.sub!(/\.git\z/, '')
diff --git a/app/models/issue.rb b/app/models/issue.rb
index ecfc33ec1a1..a88dbb3e065 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -292,7 +292,7 @@ class Issue < ActiveRecord::Base
end
def expire_etag_cache
- key = Gitlab::Routing.url_helpers.rendered_title_namespace_project_issue_path(
+ key = Gitlab::Routing.url_helpers.realtime_changes_namespace_project_issue_path(
project.namespace,
project,
self
diff --git a/app/models/repository.rb b/app/models/repository.rb
index b1563bfba8b..9153e5ae5a8 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -1163,8 +1163,6 @@ class Repository
@project.repository_storage_path
end
- delegate :gitaly_channel, :gitaly_repository, to: :raw_repository
-
def initialize_raw_repository
Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git')
end
diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml
index 8a5c8e2429c..8032d81cd91 100644
--- a/app/views/projects/builds/_sidebar.html.haml
+++ b/app/views/projects/builds/_sidebar.html.haml
@@ -136,7 +136,7 @@
- else
= build.id
- if build.retried?
- %i.fa.fa-spinner.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Job was retried' }
+ %i.fa.fa-refresh.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Job was retried' }
:javascript
new Sidebar();
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 25b8567b78f..b7515e1d91f 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -27,40 +27,42 @@
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
- .merge-request-tabs-container.scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left= icon('angle-left')
- .fade-right= icon('angle-right')
- %ul.merge-request-tabs.nav-links.scrolling-tabs
- %li.notes-tab
- = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
- Discussion
- %span.badge= @merge_request.related_notes.user.count
- - if @merge_request.source_project
- %li.commits-tab
- = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
- Commits
- %span.badge= @commits_count
- - if @pipelines.any?
- %li.pipelines-tab
- = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
- Pipelines
- %span.badge= @pipelines.size
- %li.diffs-tab
- = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do
- Changes
- %span.badge= @merge_request.diff_size
- %li#resolve-count-app.line-resolve-all-container.pull-right.prepend-top-10.hidden-xs{ "v-cloak" => true }
- %resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" }
- %div
- .line-resolve-all{ "v-show" => "discussionCount > 0",
- ":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" }
- %span.line-resolve-btn.is-disabled{ type: "button",
- ":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" }
- = render "shared/icons/icon_status_success.svg"
- %span.line-resolve-text
- {{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved
- = render "discussions/new_issue_for_all_discussions", merge_request: @merge_request
- = render "discussions/jump_to_next"
+ .merge-request-tabs-container
+ .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
+ .fade-left= icon('angle-left')
+ .fade-right= icon('angle-right')
+ .nav-links.scrolling-tabs
+ %ul.merge-request-tabs
+ %li.notes-tab
+ = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
+ Discussion
+ %span.badge= @merge_request.related_notes.user.count
+ - if @merge_request.source_project
+ %li.commits-tab
+ = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
+ Commits
+ %span.badge= @commits_count
+ - if @pipelines.any?
+ %li.pipelines-tab
+ = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
+ Pipelines
+ %span.badge= @pipelines.size
+ %li.diffs-tab
+ = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#diffs', action: 'diffs', toggle: 'tab' } do
+ Changes
+ %span.badge= @merge_request.diff_size
+ #resolve-count-app.line-resolve-all-container.prepend-top-10{ "v-cloak" => true }
+ %resolve-count{ "inline-template" => true, ":logged-out" => "#{current_user.nil?}" }
+ %div
+ .line-resolve-all{ "v-show" => "discussionCount > 0",
+ ":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" }
+ %span.line-resolve-btn.is-disabled{ type: "button",
+ ":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" }
+ = render "shared/icons/icon_status_success.svg"
+ %span.line-resolve-text
+ {{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved
+ = render "discussions/new_issue_for_all_discussions", merge_request: @merge_request
+ = render "discussions/jump_to_next"
.tab-content#diff-notes-app
#notes.notes.tab-pane.voting_notes
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 622e2f33eea..0e535117353 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -19,7 +19,7 @@
dropdown_class: "filtered-search-history-dropdown",
content_class: "filtered-search-history-dropdown-content",
title: "Recent searches" }) do
- .js-filtered-search-history-dropdown
+ .js-filtered-search-history-dropdown{ data: { project_full_path: @project.full_path } }
.filtered-search-box-input-container
.scroll-container
%ul.tokens-container.list-unstyled