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/pages/sessions/new/index.js18
-rw-r--r--app/assets/javascripts/pages/sessions/new/oauth_remember_me.js34
-rw-r--r--app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js86
-rw-r--r--app/assets/javascripts/repository/components/commit_info.vue17
-rw-r--r--app/assets/javascripts/tracking/internal_events.js11
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/blame_info.vue1
-rw-r--r--app/assets/stylesheets/pages/commits.scss4
-rw-r--r--app/controllers/groups/autocomplete_sources_controller.rb2
-rw-r--r--app/controllers/projects/autocomplete_sources_controller.rb2
-rw-r--r--app/graphql/resolvers/projects/is_forked_resolver.rb25
-rw-r--r--app/graphql/types/project_type.rb6
-rw-r--r--app/models/ci/pipeline_artifact.rb3
-rw-r--r--app/models/ci/pipeline_config.rb3
-rw-r--r--app/models/ci/pipeline_metadata.rb3
-rw-r--r--app/models/fork_network_member.rb3
-rw-r--r--app/models/user.rb2
-rw-r--r--app/services/preview_markdown_service.rb2
-rw-r--r--app/services/quick_actions/target_service.rb14
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml2
19 files changed, 156 insertions, 82 deletions
diff --git a/app/assets/javascripts/pages/sessions/new/index.js b/app/assets/javascripts/pages/sessions/new/index.js
index ee1a7633a11..21456564d3b 100644
--- a/app/assets/javascripts/pages/sessions/new/index.js
+++ b/app/assets/javascripts/pages/sessions/new/index.js
@@ -1,12 +1,14 @@
-import $ from 'jquery';
import initVueAlerts from '~/vue_alerts';
import NoEmojiValidator from '~/emoji/no_emoji_validator';
import { initLanguageSwitcher } from '~/language_switcher';
import LengthValidator from '~/validators/length_validator';
import mountEmailVerificationApplication from '~/sessions/new';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
-import OAuthRememberMe from './oauth_remember_me';
-import preserveUrlFragment from './preserve_url_fragment';
+import {
+ appendUrlFragment,
+ appendRedirectQuery,
+ toggleRememberMeQuery,
+} from './preserve_url_fragment';
import SigninTabsMemoizer from './signin_tabs_memoizer';
import UsernameValidator from './username_validator';
@@ -15,13 +17,9 @@ new LengthValidator(); // eslint-disable-line no-new
new SigninTabsMemoizer(); // eslint-disable-line no-new
new NoEmojiValidator(); // eslint-disable-line no-new
-new OAuthRememberMe({
- container: $('.js-oauth-login'),
-}).bindEvents();
-
-// Save the URL fragment from the current window location. This will be present if the user was
-// redirected to sign-in after attempting to access a protected URL that included a fragment.
-preserveUrlFragment(window.location.hash);
+appendUrlFragment();
+appendRedirectQuery();
+toggleRememberMeQuery();
initVueAlerts();
initLanguageSwitcher();
mountEmailVerificationApplication();
diff --git a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js b/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
deleted file mode 100644
index 3336b094560..00000000000
--- a/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import $ from 'jquery';
-import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
-
-/**
- * OAuth-based login buttons have a separate "remember me" checkbox.
- *
- * Toggling this checkbox adds/removes a `remember_me` parameter to the
- * login buttons' parent form action, which is passed on to the omniauth callback.
- */
-
-export default class OAuthRememberMe {
- constructor(opts = {}) {
- this.container = opts.container || '';
- }
-
- bindEvents() {
- $('#remember_me_omniauth', this.container).on('click', this.toggleRememberMe);
- }
-
- toggleRememberMe(event) {
- const rememberMe = $(event.target).is(':checked');
-
- $('.js-oauth-login form', this.container).each((_, form) => {
- const $form = $(form);
- const href = $form.attr('action');
-
- if (rememberMe) {
- $form.attr('action', mergeUrlParams({ remember_me: 1 }, href));
- } else {
- $form.attr('action', removeParams(['remember_me'], href));
- }
- });
- }
-}
diff --git a/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js b/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
index 54ec3c52f62..de48a457bcd 100644
--- a/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
+++ b/app/assets/javascripts/pages/sessions/new/preserve_url_fragment.js
@@ -1,32 +1,72 @@
-import { mergeUrlParams, setUrlFragment } from '~/lib/utils/url_utility';
+import { mergeUrlParams, removeParams, setUrlFragment } from '~/lib/utils/url_utility';
/**
- * Ensure the given URL fragment is preserved by appending it to sign-in/sign-up form actions and
- * OAuth/SAML login links.
+ * Append the fragment to all non-OAuth login form actions so it is preserved
+ * when the user is eventually redirected back to the originally requested URL.
*
* @param fragment {string} - url fragment to be preserved
*/
-export default function preserveUrlFragment(fragment = '') {
- if (fragment) {
- const normalFragment = fragment.replace(/^#/, '');
-
- // Append the fragment to all sign-in/sign-up form actions so it is preserved when the user is
- // eventually redirected back to the originally requested URL.
- const forms = document.querySelectorAll('.js-non-oauth-login form');
- Array.prototype.forEach.call(forms, (form) => {
- const actionWithFragment = setUrlFragment(form.getAttribute('action'), `#${normalFragment}`);
- form.setAttribute('action', actionWithFragment);
- });
+export function appendUrlFragment(fragment = document.location.hash) {
+ if (!fragment) {
+ return;
+ }
+
+ const normalFragment = fragment.replace(/^#/, '');
+ const forms = document.querySelectorAll('.js-non-oauth-login form');
+ forms.forEach((form) => {
+ const actionWithFragment = setUrlFragment(form.getAttribute('action'), `#${normalFragment}`);
+ form.setAttribute('action', actionWithFragment);
+ });
+}
+
+/**
+ * Append a redirect_fragment query param to all OAuth login form actions. The
+ * redirect_fragment query param will be available in the omniauth callback upon
+ * successful authentication.
+ *
+ * @param {string} fragment - url fragment to be preserved
+ */
+export function appendRedirectQuery(fragment = document.location.hash) {
+ if (!fragment) {
+ return;
+ }
+
+ const normalFragment = fragment.replace(/^#/, '');
+ const oauthForms = document.querySelectorAll('.js-oauth-login form');
+ oauthForms.forEach((oauthForm) => {
+ const newHref = mergeUrlParams(
+ { redirect_fragment: normalFragment },
+ oauthForm.getAttribute('action'),
+ );
+ oauthForm.setAttribute('action', newHref);
+ });
+}
+
+/**
+ * OAuth login buttons have a separate "remember me" checkbox.
+ *
+ * Toggling this checkbox adds/removes a `remember_me` parameter to the
+ * login form actions, which is passed on to the omniauth callback.
+ */
+export function toggleRememberMeQuery() {
+ const oauthForms = document.querySelectorAll('.js-oauth-login form');
+ const checkbox = document.querySelector('#js-remember-me-omniauth');
+
+ if (oauthForms.length === 0 || !checkbox) {
+ return;
+ }
+
+ checkbox.addEventListener('change', ({ currentTarget }) => {
+ oauthForms.forEach((oauthForm) => {
+ const href = oauthForm.getAttribute('action');
+ let newHref;
+ if (currentTarget.checked) {
+ newHref = mergeUrlParams({ remember_me: '1' }, href);
+ } else {
+ newHref = removeParams(['remember_me'], href);
+ }
- // Append a redirect_fragment query param to all oauth provider links. The redirect_fragment
- // query param will be available in the omniauth callback upon successful authentication
- const oauthForms = document.querySelectorAll('.js-oauth-login form');
- Array.prototype.forEach.call(oauthForms, (oauthForm) => {
- const newHref = mergeUrlParams(
- { redirect_fragment: normalFragment },
- oauthForm.getAttribute('action'),
- );
oauthForm.setAttribute('action', newHref);
});
- }
+ });
}
diff --git a/app/assets/javascripts/repository/components/commit_info.vue b/app/assets/javascripts/repository/components/commit_info.vue
index 319ce2cea84..9b6b0f1cb2a 100644
--- a/app/assets/javascripts/repository/components/commit_info.vue
+++ b/app/assets/javascripts/repository/components/commit_info.vue
@@ -26,6 +26,11 @@ export default {
type: Object,
required: true,
},
+ span: {
+ type: Number,
+ required: false,
+ default: null,
+ },
prevBlameLink: {
type: String,
required: false,
@@ -43,6 +48,9 @@ export default {
avatarLinkAltText() {
return sprintf(__(`%{username}'s avatar`), { username: this.commit.authorName });
},
+ truncateAuthorName() {
+ return typeof this.span === 'number' && this.span < 3;
+ },
},
methods: {
toggleShowDescription() {
@@ -102,18 +110,23 @@ export default {
@click="toggleShowDescription"
/>
</div>
- <div class="committer gl-flex-basis-full">
+ <div
+ class="committer gl-flex-basis-full"
+ :class="truncateAuthorName ? 'gl-display-inline-flex' : ''"
+ data-testid="committer"
+ >
<gl-link
v-if="commit.author"
:href="commit.author.webPath"
class="commit-author-link js-user-link"
+ :class="truncateAuthorName ? 'gl-display-inline-block gl-text-truncate' : ''"
>
{{ commit.author.name }}</gl-link
>
<template v-else>
{{ commit.authorName }}
</template>
- {{ $options.i18n.authored }}
+ {{ $options.i18n.authored }}&nbsp;
<timeago-tooltip :time="commit.authoredDate" tooltip-placement="bottom" />
</div>
<pre
diff --git a/app/assets/javascripts/tracking/internal_events.js b/app/assets/javascripts/tracking/internal_events.js
index 7da6da16d6f..d4469382be4 100644
--- a/app/assets/javascripts/tracking/internal_events.js
+++ b/app/assets/javascripts/tracking/internal_events.js
@@ -9,10 +9,13 @@ const InternalEvents = {
/**
*
* @param {string} event
+ * @param {string} category - The category of the event. This is optional and
+ * defaults to the page name where the event was triggered. It's advised not to use
+ * this parameter for new events unless absolutely necessary.
*/
- trackEvent(event) {
+ trackEvent(event, category = undefined) {
API.trackInternalEvent(event);
- Tracking.event(undefined, event, {
+ Tracking.event(category, event, {
context: {
schema: SERVICE_PING_SCHEMA,
data: {
@@ -30,8 +33,8 @@ const InternalEvents = {
mixin() {
return {
methods: {
- trackEvent(event) {
- InternalEvents.trackEvent(event);
+ trackEvent(event, category = undefined) {
+ InternalEvents.trackEvent(event, category);
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/blame_info.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/blame_info.vue
index e2fd4477f0a..3205ec2b73b 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/components/blame_info.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/blame_info.vue
@@ -30,6 +30,7 @@ export default {
class="gl-display-flex gl-absolute gl-px-3"
:style="{ top: blame.blameOffset }"
:commit="blame.commit"
+ :span="blame.span"
:prev-blame-link="blame.commitData && blame.commitData.projectBlameLink"
/>
</div>
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index b0519119bd8..e455682dcff 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -136,6 +136,10 @@
.commit-author-link {
color: $gl-text-color;
}
+
+ .commit-author-link.gl-text-truncate {
+ max-width: 20ch;
+ }
}
}
diff --git a/app/controllers/groups/autocomplete_sources_controller.rb b/app/controllers/groups/autocomplete_sources_controller.rb
index 191720f69a0..8a3ec13f720 100644
--- a/app/controllers/groups/autocomplete_sources_controller.rb
+++ b/app/controllers/groups/autocomplete_sources_controller.rb
@@ -51,7 +51,7 @@ class Groups::AutocompleteSourcesController < Groups::ApplicationController
# TODO https://gitlab.com/gitlab-org/gitlab/-/issues/388541
# type_id is a misnomer. QuickActions::TargetService actually requires an iid.
QuickActions::TargetService
- .new(nil, current_user, group: @group)
+ .new(container: @group, current_user: current_user)
.execute(params[:type], params[:type_id])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index dc10004c62b..c496a326051 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -59,7 +59,7 @@ class Projects::AutocompleteSourcesController < Projects::ApplicationController
# TODO https://gitlab.com/gitlab-org/gitlab/-/issues/388541
# type_id is a misnomer. QuickActions::TargetService actually requires an iid.
QuickActions::TargetService
- .new(project, current_user)
+ .new(container: project, current_user: current_user)
.execute(target_type, params[:type_id])
end
diff --git a/app/graphql/resolvers/projects/is_forked_resolver.rb b/app/graphql/resolvers/projects/is_forked_resolver.rb
new file mode 100644
index 00000000000..f1413543b7c
--- /dev/null
+++ b/app/graphql/resolvers/projects/is_forked_resolver.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Projects
+ class IsForkedResolver < BaseResolver
+ type GraphQL::Types::Boolean, null: false
+
+ def resolve
+ lazy_fork_network_members = BatchLoader::GraphQL.for(object.id).batch do |ids, loader|
+ ForkNetworkMember.by_projects(ids)
+ .with_fork_network
+ .find_each do |fork_network_member|
+ loader.call(fork_network_member.project_id, fork_network_member)
+ end
+ end
+
+ Gitlab::Graphql::Lazy.with_value(lazy_fork_network_members) do |fork_network_member|
+ next false if fork_network_member.nil?
+
+ fork_network_member.fork_network.root_project_id != object.id
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index aacd67e269e..bedcd08fcb4 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -685,6 +685,12 @@ module Types
description: 'Project allows assigning multiple reviewers to a merge request.',
null: false
+ field :is_forked,
+ GraphQL::Types::Boolean,
+ resolver: Resolvers::Projects::IsForkedResolver,
+ description: 'Project is forked.',
+ null: false
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
diff --git a/app/models/ci/pipeline_artifact.rb b/app/models/ci/pipeline_artifact.rb
index e0e6906f211..05c9535cef1 100644
--- a/app/models/ci/pipeline_artifact.rb
+++ b/app/models/ci/pipeline_artifact.rb
@@ -10,6 +10,9 @@ module Ci
include FileStoreMounter
include Lockable
include Presentable
+ include SafelyChangeColumnDefault
+
+ columns_changing_default :partition_id
FILE_SIZE_LIMIT = 10.megabytes.freeze
EXPIRATION_DATE = 1.week.freeze
diff --git a/app/models/ci/pipeline_config.rb b/app/models/ci/pipeline_config.rb
index 11decd3fc66..8e992aae2c5 100644
--- a/app/models/ci/pipeline_config.rb
+++ b/app/models/ci/pipeline_config.rb
@@ -3,6 +3,9 @@
module Ci
class PipelineConfig < Ci::ApplicationRecord
include Ci::Partitionable
+ include SafelyChangeColumnDefault
+
+ columns_changing_default :partition_id
self.table_name = 'ci_pipelines_config'
self.primary_key = :pipeline_id
diff --git a/app/models/ci/pipeline_metadata.rb b/app/models/ci/pipeline_metadata.rb
index 21d102374f0..39e2ef5cebb 100644
--- a/app/models/ci/pipeline_metadata.rb
+++ b/app/models/ci/pipeline_metadata.rb
@@ -4,6 +4,9 @@ module Ci
class PipelineMetadata < Ci::ApplicationRecord
include Ci::Partitionable
include Importable
+ include SafelyChangeColumnDefault
+
+ columns_changing_default :partition_id
self.primary_key = :pipeline_id
diff --git a/app/models/fork_network_member.rb b/app/models/fork_network_member.rb
index f18c306cf91..023f948d5f9 100644
--- a/app/models/fork_network_member.rb
+++ b/app/models/fork_network_member.rb
@@ -9,6 +9,9 @@ class ForkNetworkMember < ApplicationRecord
after_destroy :cleanup_fork_network
+ scope :by_projects, ->(ids) { where(project_id: ids) }
+ scope :with_fork_network, -> { joins(:fork_network).includes(:fork_network) }
+
private
def cleanup_fork_network
diff --git a/app/models/user.rb b/app/models/user.rb
index ab5572e5b19..05e35b217f4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -631,6 +631,8 @@ class User < MainClusterwide::ApplicationRecord
.trusted_with_spam)
end
+ scope :preload_user_detail, -> { preload(:user_detail) }
+
def self.supported_keyset_orderings
{
id: [:asc, :desc],
diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb
index 10aef87332a..31f79bc7164 100644
--- a/app/services/preview_markdown_service.rb
+++ b/app/services/preview_markdown_service.rb
@@ -55,7 +55,7 @@ class PreviewMarkdownService < BaseService
def find_commands_target
QuickActions::TargetService
- .new(project, current_user, group: params[:group])
+ .new(container: project, current_user: current_user, params: { group: params[:group] })
.execute(target_type, target_id)
end
diff --git a/app/services/quick_actions/target_service.rb b/app/services/quick_actions/target_service.rb
index 04ae5287302..63e2c58fc55 100644
--- a/app/services/quick_actions/target_service.rb
+++ b/app/services/quick_actions/target_service.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QuickActions
- class TargetService < BaseService
+ class TargetService < BaseContainerService
def execute(type, type_iid)
case type&.downcase
when 'workitem'
@@ -19,15 +19,15 @@ module QuickActions
# rubocop: disable CodeReuse/ActiveRecord
def work_item(type_iid)
- WorkItems::WorkItemsFinder.new(current_user, project_id: project.id).find_by(iid: type_iid)
+ WorkItems::WorkItemsFinder.new(current_user, **parent_params).find_by(iid: type_iid)
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def issue(type_iid)
- return project.issues.build if type_iid.nil?
+ return container.issues.build if type_iid.nil?
- IssuesFinder.new(current_user, project_id: project.id).find_by(iid: type_iid) || project.issues.build
+ IssuesFinder.new(current_user, **parent_params).find_by(iid: type_iid) || container.issues.build
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -42,7 +42,11 @@ module QuickActions
def commit(type_iid)
project.commit(type_iid)
end
+
+ def parent_params
+ group_container? ? { group_id: group.id } : { project_id: project.id }
+ end
end
end
-QuickActions::TargetService.prepend_mod_with('QuickActions::TargetService')
+QuickActions::TargetService.prepend_mod
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index 8197abcc787..5fbb20f7535 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -12,6 +12,6 @@
data: { testid: test_id_for_provider(provider) },
id: "oauth-login-#{provider}"
- if render_remember_me
- = render Pajamas::CheckboxTagComponent.new(name: 'remember_me_omniauth', value: nil) do |c|
+ = render Pajamas::CheckboxTagComponent.new(name: 'js-remember-me-omniauth', value: nil) do |c|
- c.with_label do
= _('Remember me')