diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-09-12 10:49:50 +0100 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-09-12 10:49:50 +0100 |
commit | 08362d80b8dc915c0812c32df5f8505c26b19b53 (patch) | |
tree | f8ecd2c9f7d71ff0bdcb502f8fde7a3ccbe995a4 /app | |
parent | 47ee81ffc62f9c119393870cf743b7ace16139c8 (diff) | |
parent | 5d3f7b133fba9bba876da5ef13c630320a920e3f (diff) | |
download | gitlab-ce-08362d80b8dc915c0812c32df5f8505c26b19b53.tar.gz |
Merge branch 'master' into 37220-es-modules
* master: (35 commits)
Use WikiPages::CreateService in spec/features/projects/wiki/user_updates_wiki_page_spec.rb
Replace the 'project/merge_requests/revert.feature' spinach test with an rspec analog
Docs group mrs list view search bar
Replace the project/milestone.feature spinach test with an rspec analog
Make all the tooltips in the same direction on the commit info box
Reset all connection schema cache after migration tests
Emoji was rendered as italic
Adds Event polyfill for IE
Add gitaly to patch update doc
Document how to swap database tables.
Replace 'project/wiki.feature' spinach test with an rspec analog
Check for sidebar cookie instead of class when resizing window
update installation and update instructions for 10.0
Replace the 'project/merge_requests/accept.feature' spinach test with an rspec analog
Remove confidential toggle checkbox and related code as no longer necessary
Bump grape_logging gem to 1.7.0 to get status codes for error messages
Expand filtered parameters to include `token`
Replace the project/team_management.feature spinach test with an rspec analog
Replace the profile/emails.feature spinach test with an rspec analog
Replace project/group_links.feature spinach test with an rspec analog
...
Diffstat (limited to 'app')
24 files changed, 182 insertions, 81 deletions
diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js index b78089525cc..cb5a9a9f6b5 100644 --- a/app/assets/javascripts/commons/polyfills.js +++ b/app/assets/javascripts/commons/polyfills.js @@ -12,4 +12,5 @@ import 'core-js/fn/symbol'; // Browser polyfills import './polyfills/custom_event'; import './polyfills/element'; +import './polyfills/event'; import './polyfills/nodelist'; diff --git a/app/assets/javascripts/commons/polyfills/custom_event.js b/app/assets/javascripts/commons/polyfills/custom_event.js index aea61b82d03..db51ade61ae 100644 --- a/app/assets/javascripts/commons/polyfills/custom_event.js +++ b/app/assets/javascripts/commons/polyfills/custom_event.js @@ -1,7 +1,12 @@ if (typeof window.CustomEvent !== 'function') { window.CustomEvent = function CustomEvent(event, params) { const evt = document.createEvent('CustomEvent'); - const evtParams = params || { bubbles: false, cancelable: false, detail: undefined }; + const evtParams = { + bubbles: false, + cancelable: false, + detail: undefined, + ...params, + }; evt.initCustomEvent(event, evtParams.bubbles, evtParams.cancelable, evtParams.detail); return evt; }; diff --git a/app/assets/javascripts/commons/polyfills/event.js b/app/assets/javascripts/commons/polyfills/event.js new file mode 100644 index 00000000000..ff5b9a1982f --- /dev/null +++ b/app/assets/javascripts/commons/polyfills/event.js @@ -0,0 +1,18 @@ +/** + * Polyfill for IE11 support. + * new Event() is not supported by IE11. + * Although `initEvent` is deprecated for modern browsers it is the one supported by IE + */ +if (typeof window.Event !== 'function') { + window.Event = function Event(event, params) { + const evt = document.createEvent('Event'); + const evtParams = { + bubbles: false, + cancelable: false, + ...params, + }; + evt.initEvent(event, evtParams.bubbles, evtParams.cancelable); + return evt; + }; + window.Event.prototype = Event; +} diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue index e115ee40219..06f6ec241f4 100644 --- a/app/assets/javascripts/issue_show/components/app.vue +++ b/app/assets/javascripts/issue_show/components/app.vue @@ -72,10 +72,6 @@ export default { required: false, default: () => [], }, - isConfidential: { - type: Boolean, - required: true, - }, markdownPreviewPath: { type: String, required: true, @@ -131,7 +127,6 @@ export default { this.showForm = true; this.store.setFormState({ title: this.state.titleText, - confidential: this.isConfidential, description: this.state.descriptionText, lockedWarningVisible: false, updateLoading: false, @@ -147,8 +142,6 @@ export default { .then((data) => { if (location.pathname !== data.web_url) { gl.utils.visitUrl(data.web_url); - } else if (data.confidential !== this.isConfidential) { - gl.utils.visitUrl(location.pathname); } return this.service.getData(); diff --git a/app/assets/javascripts/issue_show/components/fields/confidential_checkbox.vue b/app/assets/javascripts/issue_show/components/fields/confidential_checkbox.vue deleted file mode 100644 index a0ff08e9111..00000000000 --- a/app/assets/javascripts/issue_show/components/fields/confidential_checkbox.vue +++ /dev/null @@ -1,23 +0,0 @@ -<script> - export default { - props: { - formState: { - type: Object, - required: true, - }, - }, - }; -</script> - -<template> - <fieldset class="checkbox"> - <label for="issue-confidential"> - <input - type="checkbox" - value="1" - id="issue-confidential" - v-model="formState.confidential" /> - This issue is confidential and should only be visible to team members with at least Reporter access. - </label> - </fieldset> -</template> diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue index 6a2dd502fe2..28bf6c67ea5 100644 --- a/app/assets/javascripts/issue_show/components/form.vue +++ b/app/assets/javascripts/issue_show/components/form.vue @@ -4,7 +4,6 @@ import descriptionField from './fields/description.vue'; import editActions from './edit_actions.vue'; import descriptionTemplate from './fields/description_template.vue'; - import confidentialCheckbox from './fields/confidential_checkbox.vue'; export default { props: { @@ -44,7 +43,6 @@ descriptionField, descriptionTemplate, editActions, - confidentialCheckbox, }, computed: { hasIssuableTemplates() { @@ -81,8 +79,6 @@ :form-state="formState" :markdown-preview-path="markdownPreviewPath" :markdown-docs-path="markdownDocsPath" /> - <confidential-checkbox - :form-state="formState" /> <edit-actions :form-state="formState" :can-destroy="canDestroy" /> diff --git a/app/assets/javascripts/issue_show/index.js b/app/assets/javascripts/issue_show/index.js index 8053ef57e6c..aca9dec2a96 100644 --- a/app/assets/javascripts/issue_show/index.js +++ b/app/assets/javascripts/issue_show/index.js @@ -35,7 +35,6 @@ document.addEventListener('DOMContentLoaded', () => { initialDescriptionHtml: this.initialDescriptionHtml, initialDescriptionText: this.initialDescriptionText, issuableTemplates: this.issuableTemplates, - isConfidential: this.isConfidential, markdownPreviewPath: this.markdownPreviewPath, markdownDocsPath: this.markdownDocsPath, projectPath: this.projectPath, diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js index f4639e9ed2a..af8b0414266 100644 --- a/app/assets/javascripts/issue_show/stores/index.js +++ b/app/assets/javascripts/issue_show/stores/index.js @@ -3,7 +3,6 @@ export default class Store { this.state = initialState; this.formState = { title: '', - confidential: false, description: '', lockedWarningVisible: false, updateLoading: false, diff --git a/app/assets/javascripts/new_sidebar.js b/app/assets/javascripts/new_sidebar.js index fbe474f2f61..cea4f35096a 100644 --- a/app/assets/javascripts/new_sidebar.js +++ b/app/assets/javascripts/new_sidebar.js @@ -68,7 +68,7 @@ export default class NewNavSidebar { if (breakpoint === 'sm' || breakpoint === 'md') { this.toggleCollapsedSidebar(true); } else if (breakpoint === 'lg') { - const collapse = this.$sidebar.hasClass('sidebar-icons-only'); + const collapse = Cookies.get('sidebar_collapsed') === 'true'; this.toggleCollapsedSidebar(collapse); } } diff --git a/app/assets/stylesheets/framework/emojis.scss b/app/assets/stylesheets/framework/emojis.scss index 2d6bc17d4ff..527e7d57c5c 100644 --- a/app/assets/stylesheets/framework/emojis.scss +++ b/app/assets/stylesheets/framework/emojis.scss @@ -1,4 +1,5 @@ gl-emoji { + font-style: normal; display: inline-flex; vertical-align: middle; font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 8ad082f7a65..588ec1ff3bc 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -17,8 +17,11 @@ max-width: $limited-layout-width-sm; margin-left: auto; margin-right: auto; - padding-top: 64px; - padding-bottom: 64px; + + @media (min-width: $screen-md-min) { + padding-top: 64px; + padding-bottom: 64px; + } } } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index a7acaf6c728..54c3c0173ae 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -608,7 +608,7 @@ + .files, + .alert { - margin-top: 30px; + margin-top: 32px; } } } diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 66e1e607e01..df390dd5aab 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -213,7 +213,6 @@ module IssuablesHelper canUpdate: can?(current_user, :update_issue, issuable), canDestroy: can?(current_user, :destroy_issue, issuable), issuableRef: issuable.to_reference, - isConfidential: issuable.confidential, markdownPreviewPath: preview_markdown_path(@project), markdownDocsPath: help_page_path('user/markdown'), issuableTemplates: issuable_templates(issuable), diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c0114dd0256..0c8cb9ba235 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -137,15 +137,7 @@ module ProjectsHelper end def last_push_event - return unless current_user - return current_user.recent_push unless @project - - project_ids = [@project.id] - if fork = current_user.fork_of(@project) - project_ids << fork.id - end - - current_user.recent_push(project_ids) + current_user&.recent_push(@project) end def project_feature_access_select(field) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 3568e72e463..aede9b5f9da 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -247,7 +247,7 @@ class ApplicationSetting < ActiveRecord::Base housekeeping_full_repack_period: 50, housekeeping_gc_period: 200, housekeeping_incremental_repack_period: 10, - import_sources: Gitlab::ImportSources.values, + import_sources: Settings.gitlab['import_sources'], koding_enabled: false, koding_url: nil, max_artifacts_size: Settings.artifacts['max_size'], diff --git a/app/models/event.rb b/app/models/event.rb index c313bbb66f8..8e9490b66f4 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -49,7 +49,7 @@ class Event < ActiveRecord::Base belongs_to :author, class_name: "User" belongs_to :project belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations - has_one :push_event_payload, foreign_key: :event_id + has_one :push_event_payload # Callbacks after_create :reset_project_activity diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 454c90d5fc4..1f047a32c84 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -1,8 +1,5 @@ class GpgSignature < ActiveRecord::Base include ShaAttribute - include IgnorableColumn - - ignore_column :valid_signature sha_attribute :commit_sha sha_attribute :gpg_key_primary_keyid diff --git a/app/models/push_event.rb b/app/models/push_event.rb index 23ffb0d4ea8..708513c7861 100644 --- a/app/models/push_event.rb +++ b/app/models/push_event.rb @@ -30,6 +30,44 @@ class PushEvent < Event delegate :commit_count, to: :push_event_payload alias_method :commits_count, :commit_count + # Returns events of pushes that either pushed to an existing ref or created a + # new one. + def self.created_or_pushed + actions = [ + PushEventPayload.actions[:pushed], + PushEventPayload.actions[:created] + ] + + joins(:push_event_payload) + .where(push_event_payloads: { action: actions }) + end + + # Returns events of pushes to a branch. + def self.branch_events + ref_type = PushEventPayload.ref_types[:branch] + + joins(:push_event_payload) + .where(push_event_payloads: { ref_type: ref_type }) + end + + # Returns PushEvent instances for which no merge requests have been created. + def self.without_existing_merge_requests + existing_mrs = MergeRequest.except(:order) + .select(1) + .where('merge_requests.source_project_id = events.project_id') + .where('merge_requests.source_branch = push_event_payloads.ref') + + # For reasons unknown the use of #eager_load will result in the + # "push_event_payload" association not being set. Because of this we're + # using "joins" here, which does mean an additional query needs to be + # executed in order to retrieve the "push_event_association" when the + # returned PushEvent is used. + joins(:push_event_payload) + .where('NOT EXISTS (?)', existing_mrs) + .created_or_pushed + .branch_events + end + def self.sti_name PUSHED end diff --git a/app/models/user.rb b/app/models/user.rb index 26b14ade5ca..358b04ac71f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -650,20 +650,13 @@ class User < ActiveRecord::Base @personal_projects_count ||= personal_projects.count end - def recent_push(project_ids = nil) - # Get push events not earlier than 2 hours ago - events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours) - events = events.where(project_id: project_ids) if project_ids + def recent_push(project = nil) + service = Users::LastPushEventService.new(self) - # Use the latest event that has not been pushed or merged recently - events.includes(:project).recent.find do |event| - next unless event.project.repository.branch_exists?(event.branch_name) - - merge_requests = MergeRequest.where("created_at >= ?", event.created_at) - .where(source_project_id: event.project.id, - source_branch: event.branch_name) - - merge_requests.empty? + if project + service.last_event_for_project(project) + else + service.last_event_for_user end end diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index 0b7e4f187f7..6328d567a07 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -74,12 +74,19 @@ class EventCreateService # We're using an explicit transaction here so that any errors that may occur # when creating push payload data will result in the event creation being # rolled back as well. - Event.transaction do - event = create_event(project, current_user, Event::PUSHED) + event = Event.transaction do + new_event = create_event(project, current_user, Event::PUSHED) - PushEventPayloadService.new(event, push_data).execute + PushEventPayloadService + .new(new_event, push_data) + .execute + + new_event end + Users::LastPushEventService.new(current_user) + .cache_last_push_event(event) + Users::ActivityService.new(current_user, 'push').execute end diff --git a/app/services/users/last_push_event_service.rb b/app/services/users/last_push_event_service.rb new file mode 100644 index 00000000000..f2bfb60604f --- /dev/null +++ b/app/services/users/last_push_event_service.rb @@ -0,0 +1,83 @@ +module Users + # Service class for caching and retrieving the last push event of a user. + class LastPushEventService + EXPIRATION = 2.hours + + def initialize(user) + @user = user + end + + # Caches the given push event for the current user in the Rails cache. + # + # event - An instance of PushEvent to cache. + def cache_last_push_event(event) + keys = [ + project_cache_key(event.project), + user_cache_key + ] + + if event.project.forked? + keys << project_cache_key(event.project.forked_from_project) + end + + keys.each { |key| set_key(key, event.id) } + end + + # Returns the last PushEvent for the current user. + # + # This method will return nil if no event was found. + def last_event_for_user + find_cached_event(user_cache_key) + end + + # Returns the last PushEvent for the current user and the given project. + # + # project - An instance of Project for which to retrieve the PushEvent. + # + # This method will return nil if no event was found. + def last_event_for_project(project) + find_cached_event(project_cache_key(project)) + end + + def find_cached_event(cache_key) + event_id = get_key(cache_key) + + return unless event_id + + unless (event = find_event_in_database(event_id)) + # We don't want to keep querying the same data over and over when a + # merge request has been created, thus we remove the key if no event + # (meaning an MR was created) is returned. + Rails.cache.delete(cache_key) + end + + event + end + + private + + def find_event_in_database(id) + PushEvent + .without_existing_merge_requests + .find_by(id: id) + end + + def user_cache_key + "last-push-event/#{@user.id}" + end + + def project_cache_key(project) + "last-push-event/#{@user.id}/#{project.id}" + end + + def get_key(key) + Rails.cache.read(key, raw: true) + end + + def set_key(key, value) + # We're using raw values here since this takes up less space and we don't + # store complex objects. + Rails.cache.write(key, value, raw: true, expires_in: EXPIRATION) + end + end +end diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 8ab2b686f86..fcebb385a65 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -6,7 +6,7 @@ = icon('wrench') .sidebar-context-title Admin Area %ul.sidebar-top-level-items - = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts), html_options: {class: 'home'}) do + = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: {class: 'home'}) do = sidebar_link admin_root_path, title: _('Overview'), css: 'shortcuts-tree' do .nav-icon-container = custom_icon('overview') @@ -14,7 +14,7 @@ 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 + = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: { class: "fly-out-top-item" } ) do = link_to admin_root_path do %strong.fly-out-top-item-name #{ _('Overview') } @@ -52,16 +52,16 @@ %span ConvDev Index - = nav_link(controller: %w(conversational_development_index system_info background_jobs logs health_check requests_profiles)) do - = sidebar_link admin_conversational_development_index_path, title: _('Monitoring') do + = nav_link(controller: %w(system_info background_jobs logs health_check requests_profiles)) do + = sidebar_link admin_system_info_path, title: _('Monitoring') do .nav-icon-container = custom_icon('monitoring') %span.nav-item-name 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 + = nav_link(controller: %w(system_info background_jobs logs health_check requests_profiles), html_options: { class: "fly-out-top-item" } ) do + = link_to admin_system_info_path do %strong.fly-out-top-item-name #{ _('Monitoring') } %li.divider.fly-out-top-item diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 9e7fe556d88..352c2d66bab 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -16,10 +16,10 @@ .preview= image_tag "#{scheme.css_class}-scheme-preview.png" = f.radio_button :color_scheme_id, scheme.id = scheme.name + .col-sm-12 %hr - .col-sm-12 - %hr + .col-lg-4.profile-settings-sidebar %h4.prepend-top-0 Behavior diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index b8655808d89..a16ffb433a5 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -32,7 +32,7 @@ .commiter - commit_author_link = commit_author_link(commit, avatar: false, size: 24) - - commit_timeago = time_ago_with_tooltip(commit.committed_date) + - commit_timeago = time_ago_with_tooltip(commit.committed_date, placement: 'bottom') - commit_text = _('%{commit_author_link} committed %{commit_timeago}') % { commit_author_link: commit_author_link, commit_timeago: commit_timeago } #{ commit_text.html_safe } |