Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-11 09:08:40 +00:00
parent 4714aa72e3
commit 953b58d061
30 changed files with 308 additions and 48 deletions

View file

@ -176,6 +176,14 @@ export const trackSaasTrialGetStarted = () => {
});
};
export const trackTrialAcceptTerms = () => {
if (!isSupported()) {
return;
}
pushEvent('saasTrialAcceptTerms');
};
export const trackCheckout = (selectedPlan, quantity) => {
if (!isSupported()) {
return;

View file

@ -11,7 +11,7 @@ export default () => {
// eslint-disable-next-line no-new
new BlobLinePermalinkUpdater(
document.querySelector('#blob-content-holder'),
'.diff-line-num[data-line-number], .diff-line-num[data-line-number] *',
'.file-line-num[data-line-number], .file-line-num[data-line-number] *',
document.querySelectorAll('.js-data-file-blob-permalink-url, .js-blob-blame-link'),
);

View file

@ -27,6 +27,7 @@ query getBlobInfo(
fileType
language
path
blamePath
editBlobPath
gitpodBlobUrl
ideEditPath

View file

@ -7,6 +7,7 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import csrf from '~/lib/utils/csrf';
import '~/behaviors/markdown/render_gfm';
import { trackTrialAcceptTerms } from '~/google_tag_manager';
export default {
name: 'TermsApp',
@ -73,6 +74,7 @@ export default {
this.setScrollableViewportHeight();
event.target.removeEventListener(FLASH_CLOSED_EVENT, this.handleFlashClose);
},
trackTrialAcceptTerms,
},
};
</script>
@ -99,7 +101,13 @@ export default {
<gl-button type="submit">{{ $options.i18n.decline }}</gl-button>
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
</form>
<form v-if="permissions.canAccept" class="gl-ml-3" method="post" :action="paths.accept">
<form
v-if="permissions.canAccept"
class="gl-ml-3"
method="post"
:action="paths.accept"
@submit="trackTrialAcceptTerms"
>
<gl-button
type="submit"
variant="confirm"

View file

@ -51,6 +51,10 @@ export default {
required: false,
default: null,
},
blamePath: {
type: String,
required: true,
},
},
computed: {
lines() {
@ -76,6 +80,7 @@ export default {
:number="startingFrom + index + 1"
:content="line"
:language="language"
:blame-path="blamePath"
/>
</div>
<div v-else class="gl-display-flex">

View file

@ -1,5 +1,5 @@
<script>
import { GlLink, GlSafeHtmlDirective } from '@gitlab/ui';
import { GlLink, GlSafeHtmlDirective, GlTooltipDirective } from '@gitlab/ui';
import { setAttributes } from '~/lib/utils/dom_utils';
import { BIDI_CHARS, BIDI_CHARS_CLASS_LIST, BIDI_CHAR_TOOLTIP } from '../constants';
@ -9,6 +9,7 @@ export default {
},
directives: {
SafeHtml: GlSafeHtmlDirective,
GlTooltip: GlTooltipDirective,
},
props: {
number: {
@ -23,6 +24,10 @@ export default {
type: String,
required: true,
},
blamePath: {
type: String,
required: true,
},
},
computed: {
formattedContent() {
@ -58,21 +63,35 @@ export default {
};
</script>
<template>
<div class="gl-display-flex">
<div class="gl-p-0! gl-absolute gl-z-index-3 gl-border-r diff-line-num line-numbers">
<div class="gl-display-flex line-links-wrapper">
<div
class="gl-p-0! gl-absolute gl-z-index-3 diff-line-num gl-border-r gl-display-flex line-links line-numbers"
:class="firstLineClass"
>
<gl-link
v-gl-tooltip="__('View blame')"
class="gl-user-select-none gl-ml-3 gl-shadow-none! file-line-blame"
:href="`${blamePath}#L${number}`"
data-track-action="click_link"
data-track-label="file_line_action"
data-track-property="blame"
/>
<gl-link
:id="`L${number}`"
class="gl-user-select-none gl-ml-5 gl-pr-3 gl-shadow-none! file-line-num diff-line-num"
:class="firstLineClass"
class="gl-user-select-none gl-flex-grow-1 gl-justify-content-end gl-pr-3 gl-shadow-none! file-line-num"
:to="`#L${number}`"
:data-line-number="number"
data-track-action="click_link"
data-track-label="file_line_action"
data-track-property="link"
>
{{ number }}
</gl-link>
</div>
<pre
class="gl-p-0! gl-w-full gl-overflow-visible! gl-ml-11! gl-border-none! code highlight gl-line-height-normal"
class="gl-p-0! gl-w-full gl-overflow-visible! gl-border-none! code highlight gl-line-height-normal"
:class="firstLineClass"
><code><span :id="`LC${number}`" v-safe-html="formattedContent" :lang="language" class="line" data-testid="content"></span></code></pre>
</div>

View file

@ -199,6 +199,7 @@ export default {
:starting-from="firstChunk.startingFrom"
:is-highlighted="firstChunk.isHighlighted"
:language="firstChunk.language"
:blame-path="blob.blamePath"
/>
<gl-loading-icon v-if="isLoading" size="sm" class="gl-my-5" />
@ -213,6 +214,7 @@ export default {
:is-highlighted="chunk.isHighlighted"
:chunk-index="index"
:language="chunk.language"
:blame-path="blob.blamePath"
@appear="highlightChunk"
/>
</div>

View file

@ -202,6 +202,10 @@
float: none;
border-left: 1px solid $gray-100;
.file-line-num {
@include gl-min-w-9;
}
i {
float: none;
margin-right: 0;

View file

@ -48,8 +48,9 @@
a {
font-family: $monospace-font;
display: block;
white-space: nowrap;
@include gl-display-flex;
@include gl-justify-content-end;
i,
svg {
@ -90,3 +91,44 @@ td.line-numbers {
cursor: pointer;
text-decoration: underline wavy $red-500;
}
.blob-viewer {
.line-numbers {
// for server-side-rendering
.line-links {
min-width: 6.5rem;
&:first-child {
margin-top: 10px;
}
&:last-child {
margin-bottom: 10px;
}
}
// for client
&.line-links {
min-width: 6.5rem;
border-bottom-left-radius: 0;
+ pre {
margin-left: 6.5rem;
}
}
}
.line-links {
&:hover .file-line-blame::before,
&:hover .file-line-num::before,
&:focus-within .file-line-blame::before,
&:focus-within .file-line-num::before {
@include gl-visibility-visible;
}
}
.file-line-num,
.file-line-blame {
@include gl-align-items-center;
}
}

View file

@ -98,32 +98,50 @@
}
}
@mixin line-number-link($color) {
min-width: $gl-spacing-scale-9;
@mixin line-link($color, $icon) {
&::before {
@include gl-display-none;
@include gl-visibility-hidden;
@include gl-align-self-center;
@include gl-mt-2;
@include gl-mr-2;
@include gl-w-4;
@include gl-h-4;
@include gl-absolute;
@include gl-left-3;
background-color: $color;
mask-image: asset_url('icons-stacked.svg#link');
@include gl-mr-1;
@include gl-w-5;
@include gl-h-5;
background-color: rgba($color, 0.3);
mask-image: asset_url('icons-stacked.svg##{$icon}');
mask-repeat: no-repeat;
mask-size: cover;
mask-position: center;
content: '';
}
&:hover::before {
@include gl-display-inline-block;
&:hover {
&::before {
background-color: rgba($color, 0.6);
}
}
}
&:focus::before {
@include gl-display-inline-block;
@mixin line-hover-bg($color: $white-normal) {
&:hover,
&:focus-within {
background-color: darken($color, 10);
}
}
@mixin first-line-top-space($bg-color: $gray-light, $border-color: $white-normal) {
&:first-child {
.line-links {
&::before {
@include gl-absolute;
@include gl-h-3;
content: '';
bottom: 100%;
left: 0;
width: 6.5rem;
background-color: $bg-color;
border-right: 1px solid $border-color;
}
}
}
}

View file

@ -127,7 +127,19 @@ $dark-il: #de935f;
.code.dark {
// Line numbers
.file-line-num {
@include line-number-link($dark-line-num-color);
@include line-link($white, 'link');
}
.file-line-blame {
@include line-link($white, 'git');
}
.line-links {
@include line-hover-bg($dark-main-bg);
}
.line-links-wrapper {
@include first-line-top-space($dark-main-bg, $dark-code-border);
}
.line-numbers,

View file

@ -119,7 +119,19 @@ $monokai-gh: #75715e;
// Line numbers
.file-line-num {
@include line-number-link($monokai-line-num-color);
@include line-link($white, 'link');
}
.file-line-blame {
@include line-link($white, 'git');
}
.line-links {
@include line-hover-bg($monokai-bg);
}
.line-links-wrapper {
@include first-line-top-space($monokai-bg, $monokai-border);
}
.line-numbers,

View file

@ -25,7 +25,19 @@
// Line numbers
.file-line-num {
@include line-number-link($black-transparent);
@include line-link($black, 'link');
}
.file-line-blame {
@include line-link($black, 'git');
}
.line-links {
@include line-hover-bg;
}
.line-links-wrapper {
@include first-line-top-space;
}
.line-numbers,

View file

@ -122,7 +122,19 @@ $solarized-dark-il: #2aa198;
// Line numbers
.file-line-num {
@include line-number-link($solarized-dark-line-color);
@include line-link($white, 'link');
}
.file-line-blame {
@include line-link($white, 'git');
}
.line-links {
@include line-hover-bg($solarized-dark-pre-bg);
}
.line-links-wrapper {
@include first-line-top-space($solarized-dark-pre-bg, $solarized-dark-pre-border);
}
.line-numbers,

View file

@ -108,7 +108,19 @@ $solarized-light-il: #2aa198;
.code.solarized-light {
// Line numbers
.file-line-num {
@include line-number-link($solarized-light-line-color);
@include line-link($black, 'link');
}
.file-line-blame {
@include line-link($black, 'git');
}
.line-links {
@include line-hover-bg($solarized-light-pre-bg);
}
.line-links-wrapper {
@include first-line-top-space($solarized-light-pre-bg, $solarized-light-border);
}
.line-numbers,

View file

@ -95,7 +95,15 @@ $white-gc-bg: #eaf2f5;
// Line numbers
.file-line-num {
@include line-number-link($black-transparent);
@include line-link($black, 'link');
}
.file-line-blame {
@include line-link($black, 'git');
}
.line-links {
@include line-hover-bg;
}
.line-numbers,
@ -126,6 +134,10 @@ pre.code,
border-color: $white-normal;
}
.line-links-wrapper {
@include first-line-top-space;
}
&,
pre.code,
.line_holder .line_content {

View file

@ -14,6 +14,10 @@ module Users
before_action :terms
before_action only: [:index] do
push_frontend_feature_flag(:gitlab_gtm_datalayer, type: :ops)
end
layout 'terms'
feature_category :user_management

View file

@ -128,13 +128,8 @@ module MergeRequests
if draft_event = params.delete(:wip_event)
# We update the title that is provided in the params or we use the mr title
title = params[:title] || merge_request.title
# Supports both `wip` and `draft` permutations of draft_event
# This support can be removed >= %15.2
#
params[:title] = case draft_event
when 'wip' then MergeRequest.draft_title(title)
when 'draft' then MergeRequest.draft_title(title)
when 'unwip' then MergeRequest.draftless_title(title)
when 'ready' then MergeRequest.draftless_title(title)
end
end

View file

@ -1,13 +1,16 @@
#blob-content.file-content.code.js-syntax-highlight
- offset = defined?(first_line_number) ? first_line_number : 1
.line-numbers
.line-numbers{ class: "gl-p-0\!" }
- if blob.data.present?
- link = blob_link if defined?(blob_link)
- blame_link = project_blame_path(@project, tree_join(@ref, blob.path))
- blob.data.each_line.each_with_index do |_, index|
- i = index + offset
-# We're not using `link_to` because it is too slow once we get to thousands of lines.
%a.file-line-num.diff-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i }
= i
.gl-display-flex.line-links.diff-line-num
%a.file-line-blame.gl-display-flex.has-tooltip.gl-ml-3{ href: "#{blame_link}#L#{i}", title: _('View blame'), data: { track_action: "click_link", track_label: "file_line_action", track_property: "blame" } }
%a.file-line-num.gl-display-flex.gl-justify-content-end.flex-grow-1.gl-pr-3{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i, data: { track_action: "click_link", track_label: "file_line_action", track_property: "link" } }
= i
- highlight = defined?(highlight_line) && highlight_line ? highlight_line - offset : nil
.blob-content{ data: { blob_id: blob.id, path: blob.path, highlight_line: highlight, qa_selector: 'file_content' } }
%pre.code.highlight

View file

@ -138,9 +138,8 @@ module Gitlab
def self.allow_sentry(directives)
sentry_dsn = Gitlab.config.sentry.clientside_dsn
sentry_uri = URI(sentry_dsn)
sentry_uri.user = nil
append_to_directive(directives, 'connect_src', sentry_uri.to_s)
append_to_directive(directives, 'connect_src', "#{sentry_uri.scheme}://#{sentry_uri.host}")
end
def self.allow_letter_opener(directives)

View file

@ -10,6 +10,7 @@ import {
trackSaasTrialGroup,
trackSaasTrialProject,
trackSaasTrialGetStarted,
trackTrialAcceptTerms,
trackCheckout,
trackTransaction,
trackAddToCartUsageTab,
@ -255,6 +256,16 @@ describe('~/google_tag_manager/index', () => {
expect(logError).not.toHaveBeenCalled();
});
it('when trackTrialAcceptTerms is invoked', () => {
expect(spy).not.toHaveBeenCalled();
trackTrialAcceptTerms();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith({ event: 'saasTrialAcceptTerms' });
expect(logError).not.toHaveBeenCalled();
});
describe('when trackCheckout is invoked', () => {
it('with selectedPlan: 2c92a00d76f0d5060176f2fb0a5029ff', () => {
expect(spy).not.toHaveBeenCalled();

View file

@ -8,6 +8,7 @@ export const simpleViewerMock = {
language: 'javascript',
path: 'some_file.js',
webPath: 'some_file.js',
blamePath: 'blame/file.js',
editBlobPath: 'some_file.js/edit',
gitpodBlobUrl: 'https://gitpod.io#path/to/blob.js',
ideEditPath: 'some_file.js/ide/edit',

View file

@ -11,6 +11,7 @@ const DEFAULT_PROPS = {
number: 2,
content: '// Line content',
language: 'javascript',
blamePath: 'blame/file.js',
};
describe('Chunk Line component', () => {
@ -20,7 +21,7 @@ describe('Chunk Line component', () => {
wrapper = shallowMountExtended(ChunkLine, { propsData: { ...DEFAULT_PROPS, ...props } });
};
const findLink = () => wrapper.findComponent(GlLink);
const findLinks = () => wrapper.findAllComponents(GlLink);
const findContent = () => wrapper.findByTestId('content');
const findWrappedBidiChars = () => wrapper.findAllByTestId('bidi-wrapper');
@ -47,14 +48,22 @@ describe('Chunk Line component', () => {
});
});
it('renders a blame link', () => {
expect(findLinks().at(0).attributes()).toMatchObject({
href: `${DEFAULT_PROPS.blamePath}#L${DEFAULT_PROPS.number}`,
});
expect(findLinks().at(0).text()).toBe('');
});
it('renders a line number', () => {
expect(findLink().attributes()).toMatchObject({
expect(findLinks().at(1).attributes()).toMatchObject({
'data-line-number': `${DEFAULT_PROPS.number}`,
to: `#L${DEFAULT_PROPS.number}`,
id: `L${DEFAULT_PROPS.number}`,
});
expect(findLink().text()).toBe(DEFAULT_PROPS.number.toString());
expect(findLinks().at(1).text()).toBe(DEFAULT_PROPS.number.toString());
});
it('renders content', () => {

View file

@ -10,6 +10,7 @@ const DEFAULT_PROPS = {
startingFrom: 140,
totalLines: 50,
language: 'javascript',
blamePath: 'blame/file.js',
};
describe('Chunk component', () => {
@ -76,6 +77,7 @@ describe('Chunk component', () => {
number: DEFAULT_PROPS.startingFrom + 1,
content: splitContent[0],
language: DEFAULT_PROPS.language,
blamePath: DEFAULT_PROPS.blamePath,
});
});
});

View file

@ -40,7 +40,8 @@ describe('Source Viewer component', () => {
const chunk2 = generateContent('// Some source code 2', 70);
const content = chunk1 + chunk2;
const path = 'some/path.js';
const DEFAULT_BLOB_DATA = { language, rawTextBlob: content, path };
const blamePath = 'some/blame/path.js';
const DEFAULT_BLOB_DATA = { language, rawTextBlob: content, path, blamePath };
const highlightedContent = `<span data-testid='test-highlighted' id='LC1'>${content}</span><span id='LC2'></span>`;
const createComponent = async (blob = {}) => {

View file

@ -92,11 +92,11 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
context 'when sentry is configured' do
before do
stub_sentry_settings
stub_config_setting(host: 'example.com')
stub_config_setting(host: 'gitlab.example.com')
end
it 'adds sentry path to CSP without user' do
expect(directives['connect_src']).to eq("'self' ws://example.com dummy://example.com/43")
expect(directives['connect_src']).to eq("'self' ws://gitlab.example.com dummy://example.com")
end
end

View file

@ -126,4 +126,34 @@ RSpec.describe DeviseMailer do
is_expected.to have_link("Reset password", href: "#{Gitlab.config.gitlab.url}/users/password/edit?reset_password_token=faketoken")
end
end
describe '#email_changed' do
subject { described_class.email_changed(user, {}) }
let_it_be(:user) { create(:user) }
it_behaves_like 'an email sent from GitLab'
it 'is sent to the user' do
is_expected.to deliver_to user.email
end
it 'has the correct subject' do
is_expected.to have_subject 'Email Changed'
end
it 'greets the user' do
is_expected.to have_body_text /Hello, #{user.name}!/
end
context "email contains updated id" do
before do
user.update!(email: "new_email@test.com")
end
it 'includes changed email id' do
is_expected.to have_body_text /email is being changed to new_email@test.com./
end
end
end
end

View file

@ -845,6 +845,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context 'when the draft status is changed' do
let(:title) { 'New Title' }
let(:draft_title) { "Draft: #{title}" }
let!(:non_subscriber) { create(:user) }
let!(:subscriber) do
create(:user) { |u| merge_request.toggle_subscription(u, project) }
@ -857,7 +859,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
context 'removing draft status' do
before do
merge_request.update_attribute(:title, 'Draft: New Title')
merge_request.update_attribute(:title, draft_title)
end
it 'sends notifications for subscribers', :sidekiq_might_not_need_inline do
@ -870,9 +872,22 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
should_email(subscriber)
should_not_email(non_subscriber)
end
context 'when removing through wip_event param' do
it 'removes Draft from the title' do
expect { update_merge_request({ wip_event: "ready" }) }
.to change { merge_request.title }
.from(draft_title)
.to(title)
end
end
end
context 'adding draft status' do
before do
merge_request.update_attribute(:title, title)
end
it 'does not send notifications', :sidekiq_might_not_need_inline do
opts = { title: 'Draft: New title' }
@ -883,6 +898,15 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
should_not_email(subscriber)
should_not_email(non_subscriber)
end
context 'when adding through wip_event param' do
it 'adds Draft to the title' do
expect { update_merge_request({ wip_event: "draft" }) }
.to change { merge_request.title }
.from(title)
.to(draft_title)
end
end
end
end

View file

@ -12,6 +12,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let_it_be_with_refind(:private_project) { create(:project, :private, namespace: owner.namespace) }
let_it_be_with_refind(:internal_project) { create(:project, :internal, namespace: owner.namespace) }
let_it_be_with_refind(:public_project) { create(:project, :public, namespace: owner.namespace) }
let_it_be_with_refind(:public_project_in_group) { create(:project, :public, namespace: create(:group, :public)) }
let(:base_guest_permissions) do
%i[
@ -93,7 +94,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:owner_permissions) { base_owner_permissions + additional_owner_permissions }
before_all do
[private_project, internal_project, public_project].each do |project|
[private_project, internal_project, public_project, public_project_in_group].each do |project|
project.add_guest(guest)
project.add_reporter(reporter)
project.add_developer(developer)

View file

@ -24,6 +24,7 @@ RSpec.describe 'projects/blob/_viewer.html.haml' do
before do
assign(:project, project)
assign(:blob, blob)
assign(:ref, 'master')
assign(:id, File.join('master', blob.path))
controller.params[:controller] = 'projects/blob'