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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-11-11 00:09:47 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-11 00:09:47 +0300
commit7b2f94166965e60329129e5a919e2c3d88f23c7a (patch)
tree8fa395403cbffd6138b36bf36430e243f3f07f85 /app
parent6fd750c19206412cfc52b49a70b56147d839c52f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/editor/constants.js14
-rw-r--r--app/assets/javascripts/editor/extensions/example_source_editor_extension.js116
-rw-r--r--app/assets/javascripts/editor/source_editor_extension.js17
-rw-r--r--app/assets/javascripts/jobs/components/trigger_block.vue8
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/app.vue5
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/constants.js1
-rw-r--r--app/assets/javascripts/pages/groups/packages/index/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/packages/packages/index/index.js11
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql3
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue60
-rw-r--r--app/controllers/groups/packages_controller.rb4
-rw-r--r--app/controllers/projects/packages/packages_controller.rb4
-rw-r--r--app/models/suggestion.rb1
-rw-r--r--app/services/system_notes/issuables_service.rb8
-rw-r--r--app/workers/all_queues.yml9
-rw-r--r--app/workers/integrations/create_external_cross_reference_worker.rb47
16 files changed, 260 insertions, 59 deletions
diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js
index d40d19000fb..d44bfdfb966 100644
--- a/app/assets/javascripts/editor/constants.js
+++ b/app/assets/javascripts/editor/constants.js
@@ -1,15 +1,15 @@
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
-import { __ } from '~/locale';
+import { s__ } from '~/locale';
-export const SOURCE_EDITOR_INSTANCE_ERROR_NO_EL = __(
- '"el" parameter is required for createInstance()',
+export const SOURCE_EDITOR_INSTANCE_ERROR_NO_EL = s__(
+ 'SourceEditor|"el" parameter is required for createInstance()',
);
export const URI_PREFIX = 'gitlab';
export const CONTENT_UPDATE_DEBOUNCE = DEFAULT_DEBOUNCE_AND_THROTTLE_MS;
-export const ERROR_INSTANCE_REQUIRED_FOR_EXTENSION = __(
- 'Source Editor instance is required to set up an extension.',
+export const ERROR_INSTANCE_REQUIRED_FOR_EXTENSION = s__(
+ 'SourceEditor|Source Editor instance is required to set up an extension.',
);
export const EDITOR_READY_EVENT = 'editor-ready';
@@ -20,6 +20,10 @@ export const EDITOR_TYPE_DIFF = 'vs.editor.IDiffEditor';
export const EDITOR_CODE_INSTANCE_FN = 'createInstance';
export const EDITOR_DIFF_INSTANCE_FN = 'createDiffInstance';
+export const EDITOR_EXTENSION_DEFINITION_ERROR = s__(
+ 'SourceEditor|Extension definition should be either a class or a function',
+);
+
//
// EXTENSIONS' CONSTANTS
//
diff --git a/app/assets/javascripts/editor/extensions/example_source_editor_extension.js b/app/assets/javascripts/editor/extensions/example_source_editor_extension.js
new file mode 100644
index 00000000000..119a2aea9eb
--- /dev/null
+++ b/app/assets/javascripts/editor/extensions/example_source_editor_extension.js
@@ -0,0 +1,116 @@
+// THIS IS AN EXAMPLE
+//
+// This file contains a basic documented example of the Source Editor extensions'
+// API for your convenience. You can copy/paste it into your own file
+// and adjust as you see fit
+//
+
+export class MyFancyExtension {
+ /**
+ * THE LIFE-CYCLE CALLBACKS
+ */
+
+ /**
+ * Is called before the extension gets used by an instance,
+ * Use `onSetup` to setup Monaco directly:
+ * actions, keystrokes, update options, etc.
+ * Is called only once before the extension gets registered
+ *
+ * @param { Object } [setupOptions] The setupOptions object
+ * @param { Object } [instance] The Source Editor instance
+ */
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
+ onSetup(setupOptions, instance) {}
+
+ /**
+ * The first thing called after the extension is
+ * registered and used by an instance.
+ * Is called every time the extension is applied
+ *
+ * @param { Object } [instance] The Source Editor instance
+ */
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
+ onUse(instance) {}
+
+ /**
+ * Is called before un-using an extension. Can be used for time-critical
+ * actions like cleanup, reverting visual changes, and other user-facing
+ * updates.
+ *
+ * @param { Object } [instance] The Source Editor instance
+ */
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
+ onBeforeUnuse(instance) {}
+
+ /**
+ * Is called right after an extension is removed from an instance (un-used)
+ * Can be used for non time-critical tasks like cleanup on the Monaco level
+ * (removing actions, keystrokes, etc.).
+ * onUnuse() will be executed during the browser's idle period
+ * (https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback)
+ *
+ * @param { Object } [instance] The Source Editor instance
+ */
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
+ onUnuse(instance) {}
+
+ /**
+ * The public API of the extension: these are the methods that will be exposed
+ * to the end user
+ * @returns {Object}
+ */
+ provides() {
+ return {
+ basic: () => {
+ // The most basic method not depending on anything
+ // Use: instance.basic();
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return 'Foo Bar';
+ },
+ basicWithProp: () => {
+ // The methods with access to the props of the extension.
+ // The props can be either hardcoded (for example in `onSetup`), or
+ // can be dynamically passed as part of `setupOptions` object when
+ // using the extension.
+ // Use: instance.use({ definition: MyFancyExtension, setupOptions: { foo: 'bar' }});
+ return this.foo;
+ },
+ basicWithPropsAsList: (prop1, prop2) => {
+ // Just a simple method with local props
+ // The props are passed as usually.
+ // Use: instance.basicWithPropsAsList(prop1, prop2);
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return `The prop1 is ${prop1}; the prop2 is ${prop2}`;
+ },
+ basicWithInstance: (instance) => {
+ // The method accessing the instance methods: either own or provided
+ // by previously-registered extensions
+ // `instance` is always supplied to all methods in provides() as THE LAST
+ // argument.
+ // You don't need to explicitly pass instance to this method:
+ // Use: instance.basicWithInstance();
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return `We have access to the whole Instance! ${instance.alpha()}`;
+ },
+ advancedWithInstanceAndProps: ({ author, book } = {}, firstname, lastname, instance) => {
+ // Advanced method where
+ // { author, book } — are the props passed as an object
+ // prop1, prop2 — are the props passed as simple list
+ // instance — is automatically supplied, no need to pass it to
+ // the method explicitly
+ // Use: instance.advancedWithInstanceAndProps(
+ // {
+ // author: 'Franz Kafka',
+ // book: 'The Transformation'
+ // },
+ // 'Franz',
+ // 'Kafka'
+ // );
+ return `
+The author is ${author}; the book is ${book}
+The author's name is ${firstname}; the last name is ${lastname}
+We have access to the whole Instance! For example, 'instance.alpha()': ${instance.alpha()}`;
+ },
+ };
+ }
+}
diff --git a/app/assets/javascripts/editor/source_editor_extension.js b/app/assets/javascripts/editor/source_editor_extension.js
new file mode 100644
index 00000000000..664bcabcf45
--- /dev/null
+++ b/app/assets/javascripts/editor/source_editor_extension.js
@@ -0,0 +1,17 @@
+import { EDITOR_EXTENSION_DEFINITION_ERROR } from './constants';
+
+export default class EditorExtension {
+ constructor({ definition, setupOptions } = {}) {
+ if (typeof definition !== 'function') {
+ throw new Error(EDITOR_EXTENSION_DEFINITION_ERROR);
+ }
+ this.name = definition.name; // both class- and fn-based extensions have a name
+ this.setupOptions = setupOptions;
+ // eslint-disable-next-line new-cap
+ this.obj = new definition();
+ }
+
+ get api() {
+ return this.obj.provides();
+ }
+}
diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue
index fef5b37015c..b1ddede8fe8 100644
--- a/app/assets/javascripts/jobs/components/trigger_block.vue
+++ b/app/assets/javascripts/jobs/components/trigger_block.vue
@@ -84,9 +84,13 @@ export default {
>
</p>
- <gl-table :items="trigger.variables" :fields="$options.fields" small bordered>
+ <gl-table :items="trigger.variables" :fields="$options.fields" small bordered fixed>
+ <template #cell(key)="{ item }">
+ <span class="gl-overflow-break-word">{{ item.key }}</span>
+ </template>
+
<template #cell(value)="data">
- {{ getDisplayValue(data.value) }}
+ <span class="gl-overflow-break-word">{{ getDisplayValue(data.value) }}</span>
</template>
</gl-table>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/app.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/app.vue
index ee68d7db92b..45044743e27 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/app.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/app.vue
@@ -8,7 +8,6 @@ import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
import {
PROJECT_RESOURCE_TYPE,
GROUP_RESOURCE_TYPE,
- LIST_QUERY_DEBOUNCE_TIME,
GRAPHQL_PAGE_SIZE,
} from '~/packages_and_registries/package_registry/constants';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
@@ -52,7 +51,9 @@ export default {
update(data) {
return data[this.graphqlResource].packages;
},
- debounce: LIST_QUERY_DEBOUNCE_TIME,
+ skip() {
+ return !this.sort;
+ },
},
},
computed: {
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/constants.js b/app/assets/javascripts/packages_and_registries/package_registry/constants.js
index 50a8071ee41..27c3d5eb800 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js
@@ -83,5 +83,4 @@ export const INSTANCE_PACKAGE_ENDPOINT_TYPE = 'instance';
export const PROJECT_RESOURCE_TYPE = 'project';
export const GROUP_RESOURCE_TYPE = 'group';
-export const LIST_QUERY_DEBOUNCE_TIME = 50;
export const GRAPHQL_PAGE_SIZE = 20;
diff --git a/app/assets/javascripts/pages/groups/packages/index/index.js b/app/assets/javascripts/pages/groups/packages/index/index.js
index 95522573b53..f9eecff4ac4 100644
--- a/app/assets/javascripts/pages/groups/packages/index/index.js
+++ b/app/assets/javascripts/pages/groups/packages/index/index.js
@@ -1,10 +1,3 @@
-(async function packageApp() {
- if (window.gon.features.packageListApollo) {
- const newPackageList = await import('~/packages_and_registries/package_registry/pages/list');
+import packageList from '~/packages_and_registries/package_registry/pages/list';
- newPackageList.default();
- } else {
- const packageList = await import('~/packages/list/packages_list_app_bundle');
- packageList.default();
- }
-})();
+packageList();
diff --git a/app/assets/javascripts/pages/projects/packages/packages/index/index.js b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
index 95522573b53..f9eecff4ac4 100644
--- a/app/assets/javascripts/pages/projects/packages/packages/index/index.js
+++ b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
@@ -1,10 +1,3 @@
-(async function packageApp() {
- if (window.gon.features.packageListApollo) {
- const newPackageList = await import('~/packages_and_registries/package_registry/pages/list');
+import packageList from '~/packages_and_registries/package_registry/pages/list';
- newPackageList.default();
- } else {
- const packageList = await import('~/packages/list/packages_list_app_bundle');
- packageList.default();
- }
-})();
+packageList();
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
index de8de651eea..8fcae9dbad8 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
@@ -18,8 +18,11 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
}
createdAt
user {
+ id
name
+ username
webPath
+ webUrl
email
avatarUrl
status {
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index 41613bb3307..6ace0bd88f8 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -1,10 +1,16 @@
<script>
-import { GlTooltipDirective, GlLink, GlButton, GlTooltip, GlSafeHtmlDirective } from '@gitlab/ui';
+import {
+ GlTooltipDirective,
+ GlButton,
+ GlSafeHtmlDirective,
+ GlAvatarLink,
+ GlAvatarLabeled,
+} from '@gitlab/ui';
+import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { glEmojiTag } from '../../emoji';
import { __, sprintf } from '../../locale';
import CiIconBadge from './ci_badge_link.vue';
import TimeagoTooltip from './time_ago_tooltip.vue';
-import UserAvatarImage from './user_avatar/user_avatar_image.vue';
/**
* Renders header component for job and pipeline page based on UI mockups
@@ -17,10 +23,9 @@ export default {
components: {
CiIconBadge,
TimeagoTooltip,
- UserAvatarImage,
- GlLink,
GlButton,
- GlTooltip,
+ GlAvatarLink,
+ GlAvatarLabeled,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -94,6 +99,9 @@ export default {
return this.itemName;
},
+ userId() {
+ return isGid(this.user?.id) ? getIdFromGraphQLId(this.user?.id) : this.user?.id;
+ },
},
methods: {
@@ -124,24 +132,32 @@ export default {
{{ __('by') }}
<template v-if="user">
- <gl-link
- v-gl-tooltip
- :href="userPath"
- :title="user.email"
- class="js-user-link commit-committer-link"
+ <gl-avatar-link
+ :data-user-id="userId"
+ :data-username="user.username"
+ :data-name="user.name"
+ :href="user.webUrl"
+ target="_blank"
+ class="js-user-link gl-vertical-align-middle gl-mx-2 gl-align-items-center"
>
- <user-avatar-image :img-src="avatarUrl" :img-alt="userAvatarAltText" :size="24" />
- {{ user.name }}
- </gl-link>
- <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
- {{ message }}
- </gl-tooltip>
- <span
- v-if="statusTooltipHTML"
- :ref="$options.EMOJI_REF"
- v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
- :data-testid="message"
- ></span>
+ <gl-avatar-labeled
+ :size="24"
+ :src="avatarUrl"
+ :label="user.name"
+ class="gl-display-none gl-sm-display-inline-flex gl-mx-1"
+ />
+ <strong class="author gl-display-inline gl-sm-display-none!">@{{ user.username }}</strong>
+ <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
+ {{ message }}
+ </gl-tooltip>
+ <span
+ v-if="statusTooltipHTML"
+ :ref="$options.EMOJI_REF"
+ v-safe-html:[$options.safeHtmlConfig]="statusTooltipHTML"
+ class="gl-ml-2"
+ :data-testid="message"
+ ></span>
+ </gl-avatar-link>
</template>
</section>
diff --git a/app/controllers/groups/packages_controller.rb b/app/controllers/groups/packages_controller.rb
index d02a8262948..47f1816cc4c 100644
--- a/app/controllers/groups/packages_controller.rb
+++ b/app/controllers/groups/packages_controller.rb
@@ -6,10 +6,6 @@ module Groups
feature_category :package_registry
- before_action do
- push_frontend_feature_flag(:package_list_apollo, default_enabled: :yaml)
- end
-
private
def verify_packages_enabled!
diff --git a/app/controllers/projects/packages/packages_controller.rb b/app/controllers/projects/packages/packages_controller.rb
index dd7c2ad3cbd..5de71466c10 100644
--- a/app/controllers/projects/packages/packages_controller.rb
+++ b/app/controllers/projects/packages/packages_controller.rb
@@ -7,10 +7,6 @@ module Projects
feature_category :package_registry
- before_action do
- push_frontend_feature_flag(:package_list_apollo, default_enabled: :yaml)
- end
-
def show
@package = project.packages.find(params[:id])
end
diff --git a/app/models/suggestion.rb b/app/models/suggestion.rb
index ff564d87449..f1ca5c23997 100644
--- a/app/models/suggestion.rb
+++ b/app/models/suggestion.rb
@@ -50,6 +50,7 @@ class Suggestion < ApplicationRecord
next _("Can't apply as the source branch was deleted.") unless noteable.source_branch_exists?
next outdated_reason if outdated?(cached: cached) || !note.active?
next _("This suggestion already matches its content.") unless different_content?
+ next _("This file was modified for readability, and can't accept suggestions. Edit it directly.") if file_path.end_with? "ipynb"
end
end
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index 62aead352aa..94629ae7609 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -176,7 +176,13 @@ module SystemNotes
body = cross_reference_note_content(gfm_reference)
if noteable.is_a?(ExternalIssue)
- noteable.project.external_issue_tracker.create_cross_reference_note(noteable, mentioner, author)
+ Integrations::CreateExternalCrossReferenceWorker.perform_async(
+ noteable.project_id,
+ noteable.id,
+ mentioner.class.name,
+ mentioner.id,
+ author.id
+ )
else
track_cross_reference_action
create_note(NoteSummary.new(noteable, noteable.project, author, body, action: 'cross_reference'))
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index ae39bd60233..4fa74195a99 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -2231,6 +2231,15 @@
:weight: 2
:idempotent: true
:tags: []
+- :name: integrations_create_external_cross_reference
+ :worker_name: Integrations::CreateExternalCrossReferenceWorker
+ :feature_category: :integrations
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: invalid_gpg_signature_update
:worker_name: InvalidGpgSignatureUpdateWorker
:feature_category: :source_code_management
diff --git a/app/workers/integrations/create_external_cross_reference_worker.rb b/app/workers/integrations/create_external_cross_reference_worker.rb
new file mode 100644
index 00000000000..02c1315249e
--- /dev/null
+++ b/app/workers/integrations/create_external_cross_reference_worker.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Integrations
+ class CreateExternalCrossReferenceWorker
+ include ApplicationWorker
+
+ data_consistency :delayed
+
+ feature_category :integrations
+ urgency :low
+ idempotent!
+ deduplicate :until_executed, including_scheduled: true
+ loggable_arguments 2
+
+ def perform(project_id, external_issue_id, mentionable_type, mentionable_id, author_id)
+ project = Project.find_by_id(project_id) || return
+ author = User.find_by_id(author_id) || return
+ mentionable = find_mentionable(mentionable_type, mentionable_id, project) || return
+ external_issue = ExternalIssue.new(external_issue_id, project)
+
+ project.external_issue_tracker.create_cross_reference_note(
+ external_issue,
+ mentionable,
+ author
+ )
+ end
+
+ private
+
+ def find_mentionable(mentionable_type, mentionable_id, project)
+ mentionable_class = mentionable_type.safe_constantize
+
+ # Passing an invalid mentionable_class is a developer error, so we don't want to retry the job
+ # but still track the exception on production, and raise it in development.
+ unless mentionable_class && mentionable_class < Mentionable
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(ArgumentError.new("Unexpected class '#{mentionable_type}' is not a Mentionable"))
+ return
+ end
+
+ if mentionable_type == 'Commit'
+ project.commit(mentionable_id)
+ else
+ mentionable_class.find_by_id(mentionable_id)
+ end
+ end
+ end
+end