Commit 648056b8 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'ce-to-ee-2018-06-27' into 'master'

CE upstream - 2018-06-27 09:22 UTC

See merge request gitlab-org/gitlab-ee!6302
parents 2df7c585 66990906
<script> <script>
import $ from 'jquery';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import noteForm from '../../notes/components/note_form.vue'; import noteForm from '../../notes/components/note_form.vue';
import { getNoteFormData } from '../store/utils'; import { getNoteFormData } from '../store/utils';
import Autosave from '../../autosave';
import { DIFF_NOTE_TYPE, NOTE_TYPE } from '../constants';
export default { export default {
components: { components: {
...@@ -37,11 +40,28 @@ export default { ...@@ -37,11 +40,28 @@ export default {
noteableData: state => state.notes.noteableData, noteableData: state => state.notes.noteableData,
diffViewType: state => state.diffs.diffViewType, diffViewType: state => state.diffs.diffViewType,
}), }),
...mapGetters(['noteableType', 'getNotesDataByProp']), ...mapGetters(['isLoggedIn', 'noteableType', 'getNoteableData', 'getNotesDataByProp']),
},
mounted() {
if (this.isLoggedIn) {
const noteableData = this.getNoteableData;
const keys = [
NOTE_TYPE,
this.noteableType,
noteableData.id,
noteableData.diff_head_sha,
DIFF_NOTE_TYPE,
noteableData.source_project_id,
this.line.lineCode,
];
this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), keys);
}
}, },
methods: { methods: {
...mapActions(['cancelCommentForm', 'saveNote', 'fetchDiscussions']), ...mapActions(['cancelCommentForm', 'saveNote', 'fetchDiscussions']),
handleCancelCommentForm() { handleCancelCommentForm() {
this.autosave.reset();
this.cancelCommentForm({ this.cancelCommentForm({
lineCode: this.line.lineCode, lineCode: this.line.lineCode,
}); });
...@@ -82,6 +102,7 @@ export default { ...@@ -82,6 +102,7 @@ export default {
class="content discussion-form discussion-form-container discussion-notes" class="content discussion-form discussion-form-container discussion-notes"
> >
<note-form <note-form
ref="noteForm"
:is-editing="true" :is-editing="true"
:line-code="line.lineCode" :line-code="line.lineCode"
save-button-title="Comment" save-button-title="Comment"
......
...@@ -7,6 +7,7 @@ export const CONTEXT_LINE_TYPE = 'context'; ...@@ -7,6 +7,7 @@ export const CONTEXT_LINE_TYPE = 'context';
export const EMPTY_CELL_TYPE = 'empty-cell'; export const EMPTY_CELL_TYPE = 'empty-cell';
export const COMMENT_FORM_TYPE = 'commentForm'; export const COMMENT_FORM_TYPE = 'commentForm';
export const DIFF_NOTE_TYPE = 'DiffNote'; export const DIFF_NOTE_TYPE = 'DiffNote';
export const NOTE_TYPE = 'Note';
export const NEW_LINE_TYPE = 'new'; export const NEW_LINE_TYPE = 'new';
export const OLD_LINE_TYPE = 'old'; export const OLD_LINE_TYPE = 'old';
export const TEXT_DIFF_POSITION_TYPE = 'text'; export const TEXT_DIFF_POSITION_TYPE = 'text';
......
...@@ -190,12 +190,25 @@ export const getParameterByName = (name, urlToParse) => { ...@@ -190,12 +190,25 @@ export const getParameterByName = (name, urlToParse) => {
return decodeURIComponent(results[2].replace(/\+/g, ' ')); return decodeURIComponent(results[2].replace(/\+/g, ' '));
}; };
const handleSelectedRange = (range) => {
const container = range.commonAncestorContainer;
// add context to fragment if needed
if (container.tagName === 'OL') {
const parentContainer = document.createElement(container.tagName);
parentContainer.appendChild(range.cloneContents());
return parentContainer;
}
return range.cloneContents();
};
export const getSelectedFragment = () => { export const getSelectedFragment = () => {
const selection = window.getSelection(); const selection = window.getSelection();
if (selection.rangeCount === 0) return null; if (selection.rangeCount === 0) return null;
const documentFragment = document.createDocumentFragment(); const documentFragment = document.createDocumentFragment();
for (let i = 0; i < selection.rangeCount; i += 1) { for (let i = 0; i < selection.rangeCount; i += 1) {
documentFragment.appendChild(selection.getRangeAt(i).cloneContents()); const range = selection.getRangeAt(i);
documentFragment.appendChild(handleSelectedRange(range));
} }
if (documentFragment.textContent.length === 0) return null; if (documentFragment.textContent.length === 0) return null;
......
...@@ -289,7 +289,7 @@ export default class SearchAutocomplete { ...@@ -289,7 +289,7 @@ export default class SearchAutocomplete {
} }
// If the dropdown is closed, we'll open it // If the dropdown is closed, we'll open it
if (!this.dropdown.hasClass('open')) { if (!this.dropdown.hasClass('show')) {
this.loadingSuggestions = false; this.loadingSuggestions = false;
this.dropdownToggle.dropdown('toggle'); this.dropdownToggle.dropdown('toggle');
return this.searchInput.removeClass('disabled'); return this.searchInput.removeClass('disabled');
...@@ -424,9 +424,9 @@ export default class SearchAutocomplete { ...@@ -424,9 +424,9 @@ export default class SearchAutocomplete {
} }
disableAutocomplete() { disableAutocomplete() {
if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('open')) { if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('show')) {
this.searchInput.addClass('disabled'); this.searchInput.addClass('disabled');
this.dropdown.removeClass('open').trigger('hidden.bs.dropdown'); this.dropdown.removeClass('show').trigger('hidden.bs.dropdown');
this.restoreMenu(); this.restoreMenu();
} }
} }
......
# frozen_string_literal: true
class AdminEmailWorker class AdminEmailWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class ArchiveTraceWorker class ArchiveTraceWorker
include ApplicationWorker include ApplicationWorker
include PipelineBackgroundQueue include PipelineBackgroundQueue
......
# frozen_string_literal: true
class AuthorizedProjectsWorker class AuthorizedProjectsWorker
include ApplicationWorker include ApplicationWorker
prepend WaitableWorker prepend WaitableWorker
......
# frozen_string_literal: true
class BackgroundMigrationWorker class BackgroundMigrationWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class BuildCoverageWorker class BuildCoverageWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class BuildFinishedWorker class BuildFinishedWorker
prepend EE::BuildFinishedWorker prepend EE::BuildFinishedWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class BuildHooksWorker class BuildHooksWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class BuildQueueWorker class BuildQueueWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class BuildSuccessWorker class BuildSuccessWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class BuildTraceSectionsWorker class BuildTraceSectionsWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class ClusterInstallAppWorker class ClusterInstallAppWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
......
# frozen_string_literal: true
class ClusterProvisionWorker class ClusterProvisionWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
......
# frozen_string_literal: true
class ClusterWaitForAppInstallationWorker class ClusterWaitForAppInstallationWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
......
# frozen_string_literal: true
class ClusterWaitForIngressIpAddressWorker class ClusterWaitForIngressIpAddressWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
......
# frozen_string_literal: true
class CreateGpgSignatureWorker class CreateGpgSignatureWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class CreateNoteDiffFileWorker class CreateNoteDiffFileWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class CreatePipelineWorker class CreatePipelineWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class DeleteMergedBranchesWorker class DeleteMergedBranchesWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class DeleteUserWorker class DeleteUserWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class EmailReceiverWorker class EmailReceiverWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class EmailsOnPushWorker class EmailsOnPushWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class ExpireBuildArtifactsWorker class ExpireBuildArtifactsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class ExpireBuildInstanceArtifactsWorker class ExpireBuildInstanceArtifactsWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class ExpireJobCacheWorker class ExpireJobCacheWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class ExpirePipelineCacheWorker class ExpirePipelineCacheWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class GitGarbageCollectWorker class GitGarbageCollectWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class GitlabShellWorker class GitlabShellWorker
include ApplicationWorker include ApplicationWorker
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
......
# frozen_string_literal: true
class GitlabUsagePingWorker class GitlabUsagePingWorker
LEASE_TIMEOUT = 86400 LEASE_TIMEOUT = 86400
......
# frozen_string_literal: true
class GroupDestroyWorker class GroupDestroyWorker
include ApplicationWorker include ApplicationWorker
include ExceptionBacktrace include ExceptionBacktrace
......
# frozen_string_literal: true
class ImportExportProjectCleanupWorker class ImportExportProjectCleanupWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class InvalidGpgSignatureUpdateWorker class InvalidGpgSignatureUpdateWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
require 'json' require 'json'
require 'socket' require 'socket'
...@@ -69,8 +71,8 @@ class IrkerWorker ...@@ -69,8 +71,8 @@ class IrkerWorker
newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches" newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches"
newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors
privmsg = "[#{repo_name}] #{committer} has created a new branch " privmsg = "[#{repo_name}] #{committer} has created a new branch " \
privmsg += "#{branch}: #{newbranch}" "#{branch}: #{newbranch}"
sendtoirker privmsg sendtoirker privmsg
end end
...@@ -112,9 +114,7 @@ class IrkerWorker ...@@ -112,9 +114,7 @@ class IrkerWorker
url = compare_url data, project.full_path url = compare_url data, project.full_path
commits = colorize_commits data['total_commits_count'] commits = colorize_commits data['total_commits_count']
new_commits = 'new commit' new_commits = 'new commit'.pluralize(data['total_commits_count'])
new_commits += 's' if data['total_commits_count'] > 1
sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \ sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \
"to #{branch}: #{url}" "to #{branch}: #{url}"
end end
...@@ -122,8 +122,8 @@ class IrkerWorker ...@@ -122,8 +122,8 @@ class IrkerWorker
def compare_url(data, repo_path) def compare_url(data, repo_path)
sha1 = Commit.truncate_sha(data['before']) sha1 = Commit.truncate_sha(data['before'])
sha2 = Commit.truncate_sha(data['after']) sha2 = Commit.truncate_sha(data['after'])
compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare" compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare" \
compare_url += "/#{sha1}...#{sha2}" "/#{sha1}...#{sha2}"
colorize_url compare_url colorize_url compare_url
end end
...@@ -144,8 +144,7 @@ class IrkerWorker ...@@ -144,8 +144,7 @@ class IrkerWorker
def files_count(commit) def files_count(commit)
diff_size = commit.raw_deltas.size diff_size = commit.raw_deltas.size
files = "#{diff_size} file" files = "#{diff_size} file".pluralize(diff_size)
files += 's' if diff_size > 1
files files
end end
......
# frozen_string_literal: true
class IssueDueSchedulerWorker class IssueDueSchedulerWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class MergeWorker class MergeWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
# Worker to destroy projects that do not have a namespace # Worker to destroy projects that do not have a namespace
# #
# It destroys everything it can without having the info about the namespace it # It destroys everything it can without having the info about the namespace it
......
# frozen_string_literal: true
class NewIssueWorker class NewIssueWorker
include ApplicationWorker include ApplicationWorker
include NewIssuable include NewIssuable
......
# frozen_string_literal: true
class NewMergeRequestWorker class NewMergeRequestWorker
include ApplicationWorker include ApplicationWorker
include NewIssuable include NewIssuable
......
# frozen_string_literal: true
class NewNoteWorker class NewNoteWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
# @Deprecated - remove once the `object_storage_upload` queue is empty # @Deprecated - remove once the `object_storage_upload` queue is empty
# The queue has been renamed `object_storage:object_storage_background_upload` # The queue has been renamed `object_storage:object_storage_background_upload`
# #
......
# frozen_string_literal: true
class PagesDomainVerificationCronWorker class PagesDomainVerificationCronWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class PagesDomainVerificationWorker class PagesDomainVerificationWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class PagesWorker class PagesWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class PipelineHooksWorker class PipelineHooksWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PipelineMetricsWorker class PipelineMetricsWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PipelineNotificationWorker class PipelineNotificationWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PipelineProcessWorker class PipelineProcessWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PipelineScheduleWorker class PipelineScheduleWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class PipelineSuccessWorker class PipelineSuccessWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PipelineUpdateWorker class PipelineUpdateWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class PluginWorker class PluginWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class PostReceive class PostReceive
include ApplicationWorker include ApplicationWorker
prepend EE::PostReceive prepend EE::PostReceive
......
# frozen_string_literal: true
# Worker for processing individiual commit messages pushed to a repository. # Worker for processing individiual commit messages pushed to a repository.
# #
# Jobs for this worker are scheduled for every commit that is being pushed. As a # Jobs for this worker are scheduled for every commit that is being pushed. As a
......
# frozen_string_literal: true
# Worker for updating any project specific caches. # Worker for updating any project specific caches.
class ProjectCacheWorker class ProjectCacheWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class ProjectDestroyWorker class ProjectDestroyWorker
include ApplicationWorker include ApplicationWorker
include ExceptionBacktrace include ExceptionBacktrace
......
# frozen_string_literal: true
class ProjectExportWorker class ProjectExportWorker
include ApplicationWorker include ApplicationWorker
include ExceptionBacktrace include ExceptionBacktrace
......
# frozen_string_literal: true
class ProjectMigrateHashedStorageWorker class ProjectMigrateHashedStorageWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class ProjectServiceWorker class ProjectServiceWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
# Worker for updating any project specific caches. # Worker for updating any project specific caches.
class PropagateServiceTemplateWorker class PropagateServiceTemplateWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class PruneOldEventsWorker class PruneOldEventsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class ReactiveCachingWorker class ReactiveCachingWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class RebaseWorker class RebaseWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class RemoveExpiredGroupLinksWorker class RemoveExpiredGroupLinksWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RemoveExpiredMembersWorker class RemoveExpiredMembersWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RemoveOldWebHookLogsWorker class RemoveOldWebHookLogsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RemoveUnreferencedLfsObjectsWorker class RemoveUnreferencedLfsObjectsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RepositoryArchiveCacheWorker class RepositoryArchiveCacheWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RepositoryForkWorker class RepositoryForkWorker
include ApplicationWorker include ApplicationWorker
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
......
# frozen_string_literal: true
class RepositoryImportWorker class RepositoryImportWorker
include ApplicationWorker include ApplicationWorker
include ExceptionBacktrace include ExceptionBacktrace
......
# frozen_string_literal: true
class RepositoryRemoveRemoteWorker class RepositoryRemoveRemoteWorker
include ApplicationWorker include ApplicationWorker
include ExclusiveLeaseGuard include ExclusiveLeaseGuard
......
# frozen_string_literal: true
class RepositoryUpdateRemoteMirrorWorker class RepositoryUpdateRemoteMirrorWorker
UpdateAlreadyInProgressError = Class.new(StandardError) UpdateAlreadyInProgressError = Class.new(StandardError)
UpdateError = Class.new(StandardError) UpdateError = Class.new(StandardError)
......
# frozen_string_literal: true
class RequestsProfilesWorker class RequestsProfilesWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class RunPipelineScheduleWorker class RunPipelineScheduleWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class ScheduleUpdateUserActivityWorker class ScheduleUpdateUserActivityWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class StageUpdateWorker class StageUpdateWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class StorageMigratorWorker class StorageMigratorWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class StuckCiJobsWorker class StuckCiJobsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class StuckImportJobsWorker class StuckImportJobsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class StuckMergeJobsWorker class StuckMergeJobsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class SystemHookPushWorker class SystemHookPushWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class TrendingProjectsWorker class TrendingProjectsWorker
include ApplicationWorker include ApplicationWorker
include CronjobQueue include CronjobQueue
......
# frozen_string_literal: true
class UpdateHeadPipelineForMergeRequestWorker class UpdateHeadPipelineForMergeRequestWorker
include ApplicationWorker include ApplicationWorker
include PipelineQueue include PipelineQueue
......
# frozen_string_literal: true
class UpdateMergeRequestsWorker class UpdateMergeRequestsWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class UpdateUserActivityWorker class UpdateUserActivityWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class UploadChecksumWorker class UploadChecksumWorker
include ApplicationWorker include ApplicationWorker
......
# frozen_string_literal: true
class WaitForClusterCreationWorker class WaitForClusterCreationWorker
include ApplicationWorker include ApplicationWorker
include ClusterQueue include ClusterQueue
......
# frozen_string_literal: true
class WebHookWorker class WebHookWorker
include ApplicationWorker include ApplicationWorker
......
---
title: Keep lists ordered when copying only list items
merge_request: 18522
author: Jan Beckmann
type: fixed
---
title: Fix loading screen for search autocomplete dropdown
merge_request:
author:
type: fixed
---
title: Enable frozen string in app/workers/*.rb
merge_request: 19944
author: gfyoung
type: other
...@@ -17,7 +17,7 @@ describe 'Snippet elastic search', :js, :elastic do ...@@ -17,7 +17,7 @@ describe 'Snippet elastic search', :js, :elastic do
visit explore_snippets_path visit explore_snippets_path
fill_in 'search', with: 'Test' fill_in 'search', with: 'Test'
click_button 'Go' find('#search').native.send_keys(:enter)
expect(page).to have_content('Test searching for personal snippets') expect(page).to have_content('Test searching for personal snippets')
end end
...@@ -27,7 +27,7 @@ describe 'Snippet elastic search', :js, :elastic do ...@@ -27,7 +27,7 @@ describe 'Snippet elastic search', :js, :elastic do
visit explore_snippets_path visit explore_snippets_path
fill_in 'search', with: 'Test' fill_in 'search', with: 'Test'
click_button 'Go' find('#search').native.send_keys(:enter)
expect(page).to have_content('Test searching for personal snippets') expect(page).to have_content('Test searching for personal snippets')
end end
......
...@@ -493,13 +493,18 @@ module Gitlab ...@@ -493,13 +493,18 @@ module Gitlab
def tree_entry(path) def tree_entry(path)
return unless path.present? return unless path.present?
@repository.gitaly_migrate(:commit_tree_entry) do |is_migrated| # We're only interested in metadata, so limit actual data to 1 byte
if is_migrated # since Gitaly doesn't support "send no data" option.
gitaly_tree_entry(path) entry = @repository.gitaly_commit_client.tree_entry(id, path, 1)
else return unless entry
rugged_tree_entry(path)
end # To be compatible with the rugged format
end entry = entry.to_h
entry.delete(:data)
entry[:name] = File.basename(path)
entry[:type] = entry[:type].downcase
entry
end end
def to_gitaly_commit def to_gitaly_commit
...@@ -562,28 +567,6 @@ module Gitlab ...@@ -562,28 +567,6 @@ module Gitlab
SERIALIZE_KEYS SERIALIZE_KEYS
end end
def gitaly_tree_entry(path)
# We're only interested in metadata, so limit actual data to 1 byte
# since Gitaly doesn't support "send no data" option.
entry = @repository.gitaly_commit_client.tree_entry(id, path, 1)
return unless entry
# To be compatible with the rugged format
entry = entry.to_h
entry.delete(:data)
entry[:name] = File.basename(path)
entry[:type] = entry[:type].downcase
entry
end
# Is this the same as Blob.find_entry_by_path ?
def rugged_tree_entry(path)
rugged_commit.tree.path(path)
rescue Rugged::TreeError
nil
end
def gitaly_commit_author_from_rugged(author_or_committer) def gitaly_commit_author_from_rugged(author_or_committer)
Gitaly::CommitAuthor.new( Gitaly::CommitAuthor.new(
name: author_or_committer[:name].b, name: author_or_committer[:name].b,
......
...@@ -76,6 +76,13 @@ module Gitlab ...@@ -76,6 +76,13 @@ module Gitlab
end end
def tree_entry(ref, path, limit = nil) def tree_entry(ref, path, limit = nil)
if Pathname.new(path).cleanpath.to_s.start_with?('../')
# The TreeEntry RPC should return an empty reponse in this case but in
# Gitaly 0.107.0 and earlier we get an exception instead. This early return
# saves us a Gitaly roundtrip while also avoiding the exception.
return
end
request = Gitaly::TreeEntryRequest.new( request = Gitaly::TreeEntryRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
revision: encode_binary(ref), revision: encode_binary(ref),
......
...@@ -44,4 +44,59 @@ describe('CopyAsGFM', () => { ...@@ -44,4 +44,59 @@ describe('CopyAsGFM', () => {
callPasteGFM(); callPasteGFM();
}); });
}); });
describe('CopyAsGFM.copyGFM', () => {
// Stub getSelection to return a purpose-built object.
const stubSelection = (html, parentNode) => ({
getRangeAt: () => ({
commonAncestorContainer: { tagName: parentNode },
cloneContents: () => {
const fragment = document.createDocumentFragment();
const node = document.createElement('div');
node.innerHTML = html;
Array.from(node.childNodes).forEach((item) => fragment.appendChild(item));
return fragment;
},
}),
rangeCount: 1,
});
const clipboardData = {
setData() {},
};
const simulateCopy = () => {
const e = {
originalEvent: {
clipboardData,
},
preventDefault() {},
stopPropagation() {},
};
CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection);
return clipboardData;
};
beforeEach(() => spyOn(clipboardData, 'setData'));
describe('list handling', () => {
it('uses correct gfm for unordered lists', () => {
const selection = stubSelection('<li>List Item1</li><li>List Item2</li>\n', 'UL');
spyOn(window, 'getSelection').and.returnValue(selection);
simulateCopy();
const expectedGFM = '- List Item1\n- List Item2';
expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
});
it('uses correct gfm for ordered lists', () => {
const selection = stubSelection('<li>List Item1</li><li>List Item2</li>\n', 'OL');
spyOn(window, 'getSelection').and.returnValue(selection);
simulateCopy();
const expectedGFM = '1. List Item1\n1. List Item2';
expect(clipboardData.setData).toHaveBeenCalledWith('text/x-gfm', expectedGFM);
});
});
});
}); });
...@@ -19,7 +19,15 @@ describe('DiffLineNoteForm', () => { ...@@ -19,7 +19,15 @@ describe('DiffLineNoteForm', () => {
diffLines, diffLines,
line: diffLines[0], line: diffLines[0],
noteTargetLine: diffLines[0], noteTargetLine: diffLines[0],
}).$mount(); });
Object.defineProperty(component, 'isLoggedIn', {
get() {
return true;
},
});
component.$mount();
}); });
describe('methods', () => { describe('methods', () => {
...@@ -56,6 +64,15 @@ describe('DiffLineNoteForm', () => { ...@@ -56,6 +64,15 @@ describe('DiffLineNoteForm', () => {
}); });
}); });
describe('mounted', () => {
it('should init autosave', () => {
const key = 'autosave/Note/issue///DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1';
expect(component.autosave).toBeDefined();
expect(component.autosave.key).toEqual(key);
});
});
describe('template', () => { describe('template', () => {
it('should have note form', () => { it('should have note form', () => {
const { $el } = component; const { $el } = component;
......
...@@ -514,30 +514,21 @@ eos ...@@ -514,30 +514,21 @@ eos
end end
describe '#uri_type' do describe '#uri_type' do
shared_examples 'URI type' do it 'returns the URI type at the given path' do
it 'returns the URI type at the given path' do expect(commit.uri_type('files/html')).to be(:tree)
expect(commit.uri_type('files/html')).to be(:tree) expect(commit.uri_type('files/images/logo-black.png')).to be(:raw)
expect(commit.uri_type('files/images/logo-black.png')).to be(:raw) expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw)
expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw) expect(commit.uri_type('files/js/application.js')).to be(:blob)
expect(commit.uri_type('files/js/application.js')).to be(:blob)
end
it "returns nil if the path doesn't exists" do
expect(commit.uri_type('this/path/doesnt/exist')).to be_nil
end
it 'is nil if the path is nil or empty' do
expect(commit.uri_type(nil)).to be_nil
expect(commit.uri_type("")).to be_nil
end
end end
context 'when Gitaly commit_tree_entry feature is enabled' do it "returns nil if the path doesn't exists" do
it_behaves_like 'URI type' expect(commit.uri_type('this/path/doesnt/exist')).to be_nil
expect(commit.uri_type('../path/doesnt/exist')).to be_nil
end end
context 'when Gitaly commit_tree_entry feature is disabled', :disable_gitaly do it 'is nil if the path is nil or empty' do
it_behaves_like 'URI type' expect(commit.uri_type(nil)).to be_nil
expect(commit.uri_type("")).to be_nil
end end
end end
......
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