Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue26
-rw-r--r--app/assets/stylesheets/framework/common.scss2
-rw-r--r--app/controllers/dashboard/projects_controller.rb5
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/models/service.rb9
-rw-r--r--app/services/boards/issues/list_service.rb2
-rw-r--r--app/services/metrics/dashboard/grafana_metric_embed_service.rb20
7 files changed, 58 insertions, 7 deletions
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
index b90f441b8ec..5e41a155ef6 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
@@ -122,9 +122,14 @@ export default {
this.$store.subscribeAction({
after: this.handleVuexActionDispatch,
});
+
+ document.addEventListener('click', this.handleDocumentClick);
+ },
+ beforeDestroy() {
+ document.removeEventListener('click', this.handleDocumentClick);
},
methods: {
- ...mapActions(['setInitialState']),
+ ...mapActions(['setInitialState', 'toggleDropdownContents']),
/**
* This method differentiates between
* dispatched actions and calls necessary method.
@@ -138,6 +143,22 @@ export default {
this.handleDropdownClose(state.labels.filter(label => label.touched));
}
},
+ /**
+ * This method listens for document-wide click event
+ * and toggle dropdown if user clicks anywhere outside
+ * the dropdown while dropdown is visible.
+ */
+ handleDocumentClick({ target }) {
+ if (
+ this.showDropdownButton &&
+ this.showDropdownContents &&
+ !target?.classList.contains('js-sidebar-dropdown-toggle') &&
+ !this.$refs.dropdownButtonCollapsed?.$el.contains(target) &&
+ !this.$refs.dropdownContents?.$el.contains(target)
+ ) {
+ this.toggleDropdownContents();
+ }
+ },
handleDropdownClose(labels) {
// Only emit label updates if there are any labels to update
// on UI.
@@ -156,6 +177,7 @@ export default {
<div v-if="!dropdownOnly">
<dropdown-value-collapsed
v-if="allowLabelCreate"
+ ref="dropdownButtonCollapsed"
:labels="selectedLabels"
@onValueClick="handleCollapsedValueClick"
/>
@@ -167,7 +189,7 @@ export default {
<slot></slot>
</dropdown-value>
<dropdown-button v-show="showDropdownButton" />
- <dropdown-contents v-if="showDropdownButton && showDropdownContents" />
+ <dropdown-contents v-if="showDropdownButton && showDropdownContents" ref="dropdownContents" />
</div>
</div>
</template>
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 408ca249be2..20846502e85 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -413,6 +413,7 @@ img.emoji {
.prepend-left-20 { margin-left: 20px; }
.prepend-left-32 { margin-left: 32px; }
.prepend-left-64 { margin-left: 64px; }
+.append-right-2 { margin-right: 2px; }
.append-right-4 { margin-right: 4px; }
.append-right-5 { margin-right: 5px; }
.append-right-8 { margin-right: 8px; }
@@ -424,6 +425,7 @@ img.emoji {
.append-right-48 { margin-right: 48px; }
.prepend-right-32 { margin-right: 32px; }
.append-bottom-0 { margin-bottom: 0; }
+.append-bottom-2 { margin-bottom: 2px; }
.append-bottom-4 { margin-bottom: $gl-padding-4; }
.append-bottom-5 { margin-bottom: 5px; }
.append-bottom-8 { margin-bottom: $grid-size; }
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 711be67f8f9..039991e07a2 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -33,7 +33,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def starred
@projects = load_projects(params.merge(starred: true))
- .includes(:forked_from_project, :tags).page(params[:page])
+ .includes(:forked_from_project, :tags)
@groups = []
@@ -51,7 +51,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private
def projects
- @projects ||= load_projects(params.merge(non_public: true)).page(params[:page])
+ @projects ||= load_projects(params.merge(non_public: true))
end
def render_projects
@@ -73,6 +73,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
.execute
.includes(:route, :creator, :group, namespace: [:route, :owner])
.preload(:project_feature)
+ .page(finder_params[:page])
prepare_projects_for_rendering(projects)
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index d3f597c0bda..ef65b002816 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -67,6 +67,7 @@ class Issue < ApplicationRecord
scope :order_due_date_desc, -> { reorder(::Gitlab::Database.nulls_last_order('due_date', 'DESC')) }
scope :order_closest_future_date, -> { reorder(Arel.sql('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC')) }
scope :order_relative_position_asc, -> { reorder(::Gitlab::Database.nulls_last_order('relative_position', 'ASC')) }
+ scope :order_closed_date_desc, -> { reorder(closed_at: :desc) }
scope :preload_associated_models, -> { preload(:labels, project: :namespace) }
scope :with_api_entity_associations, -> { preload(:timelogs, :assignees, :author, :notes, :labels, project: [:route, { namespace: :route }] ) }
diff --git a/app/models/service.rb b/app/models/service.rb
index 91597c51fca..8f1772e67f9 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -32,9 +32,12 @@ class Service < ApplicationRecord
belongs_to :project, inverse_of: :services
has_one :service_hook
- validates :project_id, presence: true, unless: -> { template? }
+ validates :project_id, presence: true, unless: -> { template? || instance? }
+ validates :project_id, absence: true, if: -> { instance? }
validates :type, presence: true
validates :template, uniqueness: { scope: :type }, if: -> { template? }
+ validates :instance, uniqueness: { scope: :type }, if: -> { instance? }
+ validate :validate_is_instance_or_template
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
scope :issue_trackers, -> { where(category: 'issue_tracker') }
@@ -326,6 +329,10 @@ class Service < ApplicationRecord
private
+ def validate_is_instance_or_template
+ errors.add(:template, 'The service should be a service template or instance-level integration') if template? && instance?
+ end
+
def cache_project_has_external_issue_tracker
if project && !project.destroyed?
project.cache_has_external_issue_tracker
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 699fa17cb65..337710b60e0 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -10,6 +10,8 @@ module Boards
end
def execute
+ return fetch_issues.order_closed_date_desc if list&.closed?
+
fetch_issues.order_by_position_and_priority(with_cte: can_attempt_search_optimization?)
end
diff --git a/app/services/metrics/dashboard/grafana_metric_embed_service.rb b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
index 3ad3a2c609e..274057b8262 100644
--- a/app/services/metrics/dashboard/grafana_metric_embed_service.rb
+++ b/app/services/metrics/dashboard/grafana_metric_embed_service.rb
@@ -138,7 +138,9 @@ module Metrics
end
# Identifies the name of the datasource for a dashboard
- # based on the panelId query parameter found in the url
+ # based on the panelId query parameter found in the url.
+ #
+ # If no panel is specified, defaults to the first valid panel.
class DatasourceNameParser
def initialize(grafana_url, grafana_dashboard)
@grafana_url, @grafana_dashboard = grafana_url, grafana_dashboard
@@ -146,15 +148,29 @@ module Metrics
def parse
@grafana_dashboard[:dashboard][:panels]
- .find { |panel| panel[:id].to_s == query_params[:panelId] }
+ .find { |panel| panel_id ? matching_panel?(panel) : valid_panel?(panel) }
.try(:[], :datasource)
end
private
+ def panel_id
+ query_params[:panelId]
+ end
+
def query_params
Gitlab::Metrics::Dashboard::Url.parse_query(@grafana_url)
end
+
+ def matching_panel?(panel)
+ panel[:id].to_s == panel_id
+ end
+
+ def valid_panel?(panel)
+ ::Grafana::Validator
+ .new(@grafana_dashboard, nil, panel, query_params)
+ .valid?
+ end
end
end
end