summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/pages/search/show/highlight_blob_search_result.js15
-rw-r--r--app/assets/javascripts/pages/search/show/search.js2
-rw-r--r--app/controllers/admin/serverless/domains_controller.rb4
-rw-r--r--app/services/labels/promote_service.rb21
-rw-r--r--app/views/shared/notes/_hints.html.haml2
-rw-r--r--changelogs/unreleased/196384-highlight-code-search-result-line.yml5
-rw-r--r--changelogs/unreleased/23206-board-lists-lose-their-filter-label-when-said-label-becomes-a-group.yml5
-rw-r--r--changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-shared-notes.yml5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql4
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json4
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--lib/api/users.rb4
-rw-r--r--spec/frontend/fixtures/search.rb15
-rw-r--r--spec/frontend/pages/search/show/highlight_blob_search_result_spec.js15
-rw-r--r--spec/frontend/search_spec.js44
15 files changed, 116 insertions, 33 deletions
diff --git a/app/assets/javascripts/pages/search/show/highlight_blob_search_result.js b/app/assets/javascripts/pages/search/show/highlight_blob_search_result.js
new file mode 100644
index 00000000000..e17c87735b4
--- /dev/null
+++ b/app/assets/javascripts/pages/search/show/highlight_blob_search_result.js
@@ -0,0 +1,15 @@
+export default () => {
+ const highlightLineClass = 'hll';
+ const contentBody = document.getElementById('content-body');
+ const searchTerm = contentBody.querySelector('.js-search-input').value.toLowerCase();
+ const blobs = contentBody.querySelectorAll('.blob-result');
+
+ blobs.forEach(blob => {
+ const lines = blob.querySelectorAll('.line');
+ lines.forEach(line => {
+ if (line.textContent.toLowerCase().includes(searchTerm)) {
+ line.classList.add(highlightLineClass);
+ }
+ });
+ });
+};
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
index dff9d855b67..4050f2f13f1 100644
--- a/app/assets/javascripts/pages/search/show/search.js
+++ b/app/assets/javascripts/pages/search/show/search.js
@@ -5,9 +5,11 @@ import Api from '~/api';
import { __ } from '~/locale';
import Project from '~/pages/projects/project';
import refreshCounts from './refresh_counts';
+import setHighlightClass from './highlight_blob_search_result';
export default class Search {
constructor() {
+ setHighlightClass();
const $groupDropdown = $('.js-search-group-dropdown');
const $projectDropdown = $('.js-search-project-dropdown');
diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb
index 9741a0716f2..1d4f10e033f 100644
--- a/app/controllers/admin/serverless/domains_controller.rb
+++ b/app/controllers/admin/serverless/domains_controller.rb
@@ -9,7 +9,7 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
end
def create
- if PagesDomain.instance_serverless.count > 0
+ if PagesDomain.instance_serverless.exists?
return redirect_to admin_serverless_domains_path, notice: _('An instance-level serverless domain already exists.')
end
@@ -31,7 +31,7 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
end
def destroy
- if domain.serverless_domain_clusters.count > 0
+ if domain.serverless_domain_clusters.exists?
return redirect_to admin_serverless_domains_path,
status: :conflict,
notice: _('Domain cannot be deleted while associated to one or more clusters.')
diff --git a/app/services/labels/promote_service.rb b/app/services/labels/promote_service.rb
index e73e6476c12..cc91fd4b4d2 100644
--- a/app/services/labels/promote_service.rb
+++ b/app/services/labels/promote_service.rb
@@ -13,13 +13,8 @@ module Labels
new_label = clone_label_to_group_label(label)
label_ids_for_merge(new_label).find_in_batches(batch_size: BATCH_SIZE) do |batched_ids|
- update_issuables(new_label, batched_ids)
- update_resource_label_events(new_label, batched_ids)
- update_issue_board_lists(new_label, batched_ids)
- update_priorities(new_label, batched_ids)
- subscribe_users(new_label, batched_ids)
- # Order is important, project labels need to be last
- update_project_labels(batched_ids)
+ update_old_label_relations(new_label, batched_ids)
+ destroy_project_labels(batched_ids)
end
# We skipped validations during creation. Let's run them now, after deleting conflicting labels
@@ -32,6 +27,14 @@ module Labels
private
+ def update_old_label_relations(new_label, old_label_ids)
+ update_issuables(new_label, old_label_ids)
+ update_resource_label_events(new_label, old_label_ids)
+ update_issue_board_lists(new_label, old_label_ids)
+ update_priorities(new_label, old_label_ids)
+ subscribe_users(new_label, old_label_ids)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def subscribe_users(new_label, label_ids)
# users can be subscribed to multiple labels that will be merged into the group one
@@ -86,7 +89,7 @@ module Labels
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
- def update_project_labels(label_ids)
+ def destroy_project_labels(label_ids)
Label.where(id: label_ids).destroy_all # rubocop: disable DestroyAll
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -105,3 +108,5 @@ module Labels
end
end
end
+
+Labels::PromoteService.prepend_if_ee('EE::Labels::PromoteService')
diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml
index fae7d6526e8..902a6e9b363 100644
--- a/app/views/shared/notes/_hints.html.haml
+++ b/app/views/shared/notes/_hints.html.haml
@@ -17,7 +17,7 @@
-# Populated by app/assets/javascripts/dropzone_input.js
%span.uploading-progress 0%
%span.uploading-spinner
- = icon('spinner spin', class: 'toolbar-button-icon')
+ .toolbar-button-icon.spinner.align-text-top
%span.uploading-error-container.hide
%span.uploading-error-icon
diff --git a/changelogs/unreleased/196384-highlight-code-search-result-line.yml b/changelogs/unreleased/196384-highlight-code-search-result-line.yml
new file mode 100644
index 00000000000..68de400ec18
--- /dev/null
+++ b/changelogs/unreleased/196384-highlight-code-search-result-line.yml
@@ -0,0 +1,5 @@
+---
+title: Highlight line which includes search term is code search results
+merge_request: 22914
+author: Alex Terekhov (terales)
+type: added
diff --git a/changelogs/unreleased/23206-board-lists-lose-their-filter-label-when-said-label-becomes-a-group.yml b/changelogs/unreleased/23206-board-lists-lose-their-filter-label-when-said-label-becomes-a-group.yml
new file mode 100644
index 00000000000..d79ec320e95
--- /dev/null
+++ b/changelogs/unreleased/23206-board-lists-lose-their-filter-label-when-said-label-becomes-a-group.yml
@@ -0,0 +1,5 @@
+---
+title: Update board scopes when promoting a label
+merge_request: 27662
+author:
+type: fixed
diff --git a/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-shared-notes.yml b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-shared-notes.yml
new file mode 100644
index 00000000000..c370e26c316
--- /dev/null
+++ b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-shared-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate .fa-spinner to .spinner for app/views/shared/notes
+merge_request: 25028
+author: nuwe1
+type: other
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 6d02b2905e2..2d78174d669 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -2548,7 +2548,7 @@ type EpicIssue implements Noteable {
epicIssueId: ID!
"""
- Current health status. Available only when feature flag `save_issuable_health_status` is enabled
+ Current health status. Returns null if `save_issuable_health_status` feature flag is disabled.
"""
healthStatus: HealthStatus
@@ -3539,7 +3539,7 @@ type Issue implements Noteable {
epic: Epic
"""
- Current health status. Available only when feature flag `save_issuable_health_status` is enabled
+ Current health status. Returns null if `save_issuable_health_status` feature flag is disabled.
"""
healthStatus: HealthStatus
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 40053199d72..2be4573cafe 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -7397,7 +7397,7 @@
},
{
"name": "healthStatus",
- "description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled",
+ "description": "Current health status. Returns null if `save_issuable_health_status` feature flag is disabled.",
"args": [
],
@@ -10125,7 +10125,7 @@
},
{
"name": "healthStatus",
- "description": "Current health status. Available only when feature flag `save_issuable_health_status` is enabled",
+ "description": "Current health status. Returns null if `save_issuable_health_status` feature flag is disabled.",
"args": [
],
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index cce8603a54f..6a79a407dac 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -419,7 +419,7 @@ Relationship between an epic and an issue
| `dueDate` | Time | Due date of the issue |
| `epic` | Epic | Epic to which this issue belongs |
| `epicIssueId` | ID! | ID of the epic-issue relation |
-| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled |
+| `healthStatus` | HealthStatus | Current health status. Returns null if `save_issuable_health_status` feature flag is disabled. |
| `id` | ID | Global ID of the epic-issue relation |
| `iid` | ID! | Internal ID of the issue |
| `milestone` | Milestone | Milestone of the issue |
@@ -540,7 +540,7 @@ Autogenerated return type of EpicTreeReorder
| `downvotes` | Int! | Number of downvotes the issue has received |
| `dueDate` | Time | Due date of the issue |
| `epic` | Epic | Epic to which this issue belongs |
-| `healthStatus` | HealthStatus | Current health status. Available only when feature flag `save_issuable_health_status` is enabled |
+| `healthStatus` | HealthStatus | Current health status. Returns null if `save_issuable_health_status` feature flag is disabled. |
| `iid` | ID! | Internal ID of the issue |
| `milestone` | Milestone | Milestone of the issue |
| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 1ca222b4ed5..1694f3fe3fb 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -206,11 +206,11 @@ module API
conflict!('Email has already been taken') if params[:email] &&
User.by_any_email(params[:email].downcase)
- .where.not(id: user.id).count > 0
+ .where.not(id: user.id).exists?
conflict!('Username has already been taken') if params[:username] &&
User.by_username(params[:username])
- .where.not(id: user.id).count > 0
+ .where.not(id: user.id).exists?
user_params = declared_params(include_missing: false)
diff --git a/spec/frontend/fixtures/search.rb b/spec/frontend/fixtures/search.rb
index 025cc53c745..cbe3e373986 100644
--- a/spec/frontend/fixtures/search.rb
+++ b/spec/frontend/fixtures/search.rb
@@ -16,4 +16,19 @@ describe SearchController, '(JavaScript fixtures)', type: :controller do
expect(response).to be_successful
end
+
+ context 'search within a project' do
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
+ let(:project) { create(:project, :public, :repository, namespace: namespace, path: 'search-project') }
+
+ it 'search/blob_search_result.html' do
+ get :show, params: {
+ search: 'Send',
+ project_id: project.id,
+ scope: :blobs
+ }
+
+ expect(response).to be_successful
+ end
+ end
end
diff --git a/spec/frontend/pages/search/show/highlight_blob_search_result_spec.js b/spec/frontend/pages/search/show/highlight_blob_search_result_spec.js
new file mode 100644
index 00000000000..4083a65df75
--- /dev/null
+++ b/spec/frontend/pages/search/show/highlight_blob_search_result_spec.js
@@ -0,0 +1,15 @@
+import setHighlightClass from '~/pages/search/show/highlight_blob_search_result';
+
+const fixture = 'search/blob_search_result.html';
+
+describe('pages/search/show/highlight_blob_search_result', () => {
+ preloadFixtures(fixture);
+
+ beforeEach(() => loadFixtures(fixture));
+
+ it('highlights lines with search term occurrence', () => {
+ setHighlightClass();
+
+ expect(document.querySelectorAll('.blob-result .hll').length).toBe(11);
+ });
+});
diff --git a/spec/frontend/search_spec.js b/spec/frontend/search_spec.js
index af93fa88f72..1573365538c 100644
--- a/spec/frontend/search_spec.js
+++ b/spec/frontend/search_spec.js
@@ -1,8 +1,10 @@
import $ from 'jquery';
import Api from '~/api';
import Search from '~/pages/search/show/search';
+import setHighlightClass from '~/pages/search/show/highlight_blob_search_result';
jest.mock('~/api');
+jest.mock('~/pages/search/show/highlight_blob_search_result');
describe('Search', () => {
const fixturePath = 'search/show.html';
@@ -16,27 +18,41 @@ describe('Search', () => {
preloadFixtures(fixturePath);
- beforeEach(() => {
- loadFixtures(fixturePath);
- new Search(); // eslint-disable-line no-new
+ describe('constructor side effects', () => {
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('highlights lines with search terms in blob search results', () => {
+ new Search(); // eslint-disable-line no-new
+
+ expect(setHighlightClass).toHaveBeenCalled();
+ });
});
- it('requests groups from backend when filtering', () => {
- jest.spyOn(Api, 'groups').mockImplementation(term => {
- expect(term).toBe(searchTerm);
+ describe('dropdown behavior', () => {
+ beforeEach(() => {
+ loadFixtures(fixturePath);
+ new Search(); // eslint-disable-line no-new
});
- const inputElement = fillDropdownInput('.js-search-group-dropdown');
+ it('requests groups from backend when filtering', () => {
+ jest.spyOn(Api, 'groups').mockImplementation(term => {
+ expect(term).toBe(searchTerm);
+ });
- $(inputElement).trigger('input');
- });
+ const inputElement = fillDropdownInput('.js-search-group-dropdown');
- it('requests projects from backend when filtering', () => {
- jest.spyOn(Api, 'projects').mockImplementation(term => {
- expect(term).toBe(searchTerm);
+ $(inputElement).trigger('input');
});
- const inputElement = fillDropdownInput('.js-search-project-dropdown');
- $(inputElement).trigger('input');
+ it('requests projects from backend when filtering', () => {
+ jest.spyOn(Api, 'projects').mockImplementation(term => {
+ expect(term).toBe(searchTerm);
+ });
+ const inputElement = fillDropdownInput('.js-search-project-dropdown');
+
+ $(inputElement).trigger('input');
+ });
});
});