Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2a069cd8b6
commit
d13bafb390
|
|
@ -13,3 +13,4 @@ spec/frontend/lib/utils/secret_detection_spec.js:generic-api-key:55
|
|||
spec/frontend/lib/utils/secret_detection_spec.js:generic-api-key:57
|
||||
spec/frontend/lib/utils/secret_detection_spec.js:gitlab-pat:28
|
||||
d39da82ae304b8813a8fb2c79c3d7cd6f173590e:doc/api/groups.md:gitlab-pat:2342
|
||||
doc/api/packages/conan_v2.md:jwt:82
|
||||
|
|
|
|||
|
|
@ -292,10 +292,9 @@ export const VALUE_STREAM_METRIC_METADATA = {
|
|||
docsLink: helpPagePath('user/group/issues_analytics/_index'),
|
||||
},
|
||||
[CONTRIBUTOR_METRICS.COUNT]: {
|
||||
description: s__(
|
||||
'ValueStreamAnalytics|Number of monthly unique users with contributions in the group.',
|
||||
),
|
||||
description: s__('ValueStreamAnalytics|Number of monthly unique users with contributions.'),
|
||||
groupLink: '-/contribution_analytics',
|
||||
projectLink: '-/graphs/master?ref_type=heads',
|
||||
docsLink: helpPagePath('user/profile/contributions_calendar.html', {
|
||||
anchor: 'user-contribution-events',
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import { orderBy } from 'lodash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
convertObjectPropsToCamelCase,
|
||||
convertObjectPropsToSnakeCase,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import { memoize } from 'lodash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
|
||||
export const hasSelection = (tiptapEditor) => {
|
||||
const { from, to } = tiptapEditor.state.selection;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { initToggle } from '~/toggles';
|
||||
import toast from '~/vue_shared/plugins/global_toast';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { initToggle } from '~/toggles';
|
||||
import toast from '~/vue_shared/plugins/global_toast';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import Visibility from 'visibilityjs';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
|
||||
import Poll from '~/lib/utils/poll';
|
||||
import { __ } from '~/locale';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<script>
|
||||
import { GlAlert, GlForm } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { s__ } from '~/locale';
|
||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlAvatarLabeled, GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import { debounce } from 'lodash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { s__ } from '~/locale';
|
||||
import { getGroups, getDescendentGroups, getProjectShareLocations } from '~/rest_api';
|
||||
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { buildApiUrl } from '~/api/api_utils';
|
||||
|
||||
import { GITLAB_COM_BASE_PATH } from '~/jira_connect/subscriptions/constants';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// This is the only file allowed to import directly from the package.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import axios from 'axios';
|
||||
import { registerCaptchaModalInterceptor } from '~/captcha/captcha_modal_axios_interceptor';
|
||||
import setupAxiosStartupCalls from './axios_startup_calls';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { roleDropdownItems, initialSelectedRole } from '~/members/utils';
|
||||
import {
|
||||
GROUP_LINK_ACCESS_LEVEL_PROPERTY_NAME,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { createAlert } from '~/alert';
|
||||
import { __ } from '~/locale';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlFilteredSearchSuggestion } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { createAlert } from '~/alert';
|
||||
import { __ } from '~/locale';
|
||||
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
duoFeedbackText() {
|
||||
return sprintf(
|
||||
__(
|
||||
'Rate this response %{separator} %{codeStart}%{botUser}%{codeEnd} in reply for more questions',
|
||||
'Rate this response %{separator} Mention %{codeStart}%{botUser}%{codeEnd} to continue the conversation.',
|
||||
),
|
||||
{
|
||||
separator: '•',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { pinia } from '~/pinia/instance';
|
||||
import { DiffFile } from '~/rapid_diffs/diff_file';
|
||||
import FileBrowserToggle from '~/diffs/components/file_browser_toggle.vue';
|
||||
|
|
|
|||
|
|
@ -12,9 +12,19 @@ export default {
|
|||
default: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
pageKey() {
|
||||
return this.$route.params.iid || this.$route.name;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-view :new-comment-template-paths="newCommentTemplatePaths" :with-tabs="withTabs" />
|
||||
<router-view
|
||||
:key="pageKey"
|
||||
:new-comment-template-paths="newCommentTemplatePaths"
|
||||
:with-tabs="withTabs"
|
||||
data-testid="work-item-router-view"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { s__, __ } from '~/locale';
|
|||
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
|
||||
import { STATE_OPEN, WORK_ITEM_TYPE_NAME_TASK, i18n } from '~/work_items/constants';
|
||||
import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
|
||||
import gfmEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
|
||||
import glAbilitiesMixin from '~/vue_shared/mixins/gl_abilities_mixin';
|
||||
import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
|
||||
|
|
@ -40,6 +41,7 @@ export default {
|
|||
constantOptions: {
|
||||
markdownDocsPath: helpPagePath('user/markdown'),
|
||||
},
|
||||
gfmEventHub,
|
||||
components: {
|
||||
CommentFieldLayout,
|
||||
GlButton,
|
||||
|
|
@ -376,6 +378,7 @@ export default {
|
|||
:autofocus="autofocus"
|
||||
:restricted-tool-bar-items="restrictedToolBarItems"
|
||||
@input="setCommentText"
|
||||
@keydown.up="$options.gfmEventHub.$emit('edit-current-user-last-note', $event)"
|
||||
@keydown.meta.enter="submitForm()"
|
||||
@keydown.ctrl.enter="submitForm()"
|
||||
@keydown.esc.stop="cancelEditing"
|
||||
|
|
|
|||
|
|
@ -286,7 +286,12 @@ export default {
|
|||
@cancelEditing="$emit('cancelEditing')"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
<timeline-entry-item v-else :data-note-id="noteId" class="note note-discussion gl-px-0">
|
||||
<timeline-entry-item
|
||||
v-else
|
||||
:data-note-id="noteId"
|
||||
:data-discussion-id="discussionId"
|
||||
class="note note-discussion gl-px-0"
|
||||
>
|
||||
<div class="timeline-content">
|
||||
<div class="discussion">
|
||||
<div class="discussion-body">
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { updateDraft, clearDraft } from '~/lib/utils/autosave';
|
|||
import { renderMarkdown } from '~/notes/utils';
|
||||
import { getLocationHash } from '~/lib/utils/url_utility';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import gfmEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import EditedAt from '~/issues/show/components/edited.vue';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import NoteHeader from '~/notes/components/note_header.vue';
|
||||
|
|
@ -216,6 +217,12 @@ export default {
|
|||
return this.note.discussion.resolvedBy;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
gfmEventHub.$on('edit-note', this.handleEditNote);
|
||||
},
|
||||
beforeDestroy() {
|
||||
gfmEventHub.$off('edit-note', this.handleEditNote);
|
||||
},
|
||||
|
||||
apollo: {
|
||||
workItem: {
|
||||
|
|
@ -247,6 +254,11 @@ export default {
|
|||
this.isEditing = true;
|
||||
updateDraft(this.autosaveKey, this.note.body);
|
||||
},
|
||||
handleEditNote({ note }) {
|
||||
if (this.hasAdminPermission && note.id === this.note.id) {
|
||||
this.startEditing();
|
||||
}
|
||||
},
|
||||
async updateNote({ commentText, executeOptimisticResponse = true }) {
|
||||
try {
|
||||
this.isEditing = false;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
TYPENAME_DISCUSSION_NOTE,
|
||||
TYPENAME_NOTE,
|
||||
TYPENAME_GROUP,
|
||||
TYPENAME_USER,
|
||||
} from '~/graphql_shared/constants';
|
||||
import { Mousetrap } from '~/lib/mousetrap';
|
||||
import { ISSUABLE_COMMENT_OR_REPLY, keysFor } from '~/behaviors/shortcuts/keybindings';
|
||||
|
|
@ -239,6 +240,11 @@ export default {
|
|||
|
||||
return visibleNotes;
|
||||
},
|
||||
userComments() {
|
||||
return this.notesArray
|
||||
.flatMap((discussion) => discussion.notes.nodes)
|
||||
.filter((note) => !note.system);
|
||||
},
|
||||
commentsDisabled() {
|
||||
return this.discussionFilter === WORK_ITEM_NOTES_FILTER_ONLY_HISTORY;
|
||||
},
|
||||
|
|
@ -278,11 +284,13 @@ export default {
|
|||
}
|
||||
if (this.canCreateNote) {
|
||||
Mousetrap.bind(keysFor(ISSUABLE_COMMENT_OR_REPLY), (e) => this.quoteReply(e));
|
||||
gfmEventHub.$on('edit-current-user-last-note', this.editCurrentUserLastNote);
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.canCreateNote) {
|
||||
Mousetrap.unbind(keysFor(ISSUABLE_COMMENT_OR_REPLY), this.quoteReply);
|
||||
gfmEventHub.$off('edit-current-user-last-note', this.editCurrentUserLastNote);
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
|
|
@ -385,6 +393,36 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
editCurrentUserLastNote(e) {
|
||||
const currentUserId = convertToGraphQLId(TYPENAME_USER, gon.current_user_id);
|
||||
const isToplevelCommentForm = Boolean(e.target.closest('.js-comment-form'));
|
||||
let availableNotes = [];
|
||||
|
||||
if (isToplevelCommentForm) {
|
||||
// User hit `Up` key from top-level comment form, populate all the comments,
|
||||
// also ensure to reverse them only if sort order is set to newest-first (DESC).
|
||||
availableNotes = this.formAtTop ? [...this.userComments] : [...this.userComments].reverse();
|
||||
} else {
|
||||
// User hit `Up` key from a comment form within an existing thread, populate
|
||||
// all the comments, from this thread, and reverse order so the latest comments come first.
|
||||
const discussionId = convertToGraphQLId(
|
||||
TYPENAME_DISCUSSION_NOTE,
|
||||
e.target.closest('.js-timeline-entry').dataset.discussionId,
|
||||
);
|
||||
availableNotes = [
|
||||
...this.notesArray.find((discussion) => discussion.id === discussionId).notes.nodes,
|
||||
].reverse();
|
||||
}
|
||||
|
||||
// Find current user's last note.
|
||||
const currentUserLastNote = availableNotes.find((note) => note.author.id === currentUserId);
|
||||
|
||||
if (!currentUserLastNote) return;
|
||||
|
||||
gfmEventHub.$emit('edit-note', {
|
||||
note: currentUserLastNote,
|
||||
});
|
||||
},
|
||||
getDiscussionIdFromSelection() {
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount <= 0) return null;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
= webpack_bundle_tag 'analytics'
|
||||
= javascript_tag do
|
||||
:plain
|
||||
window.snowplowOptions = #{Gitlab::Tracking.options(@group).to_json}
|
||||
window.snowplowOptions = #{Gitlab::Tracking.frontend_client_options(@group).to_json}
|
||||
|
||||
gl = window.gl || {};
|
||||
gl.snowplowStandardContext = #{Gitlab::Tracking::StandardContext.new(
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ if Gitlab::Runtime.console?
|
|||
init_autocomplete
|
||||
end
|
||||
|
||||
unless ::Gitlab.next_rails?
|
||||
def init_autocomplete
|
||||
return unless Rails.env.production?
|
||||
def init_autocomplete
|
||||
return if ::Gitlab.next_rails?
|
||||
return unless Rails.env.production?
|
||||
|
||||
# IRB_USE_AUTOCOMPLETE was added in https://github.com/ruby/irb/pull/469
|
||||
IRB.conf[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "false") == "true"
|
||||
end
|
||||
# IRB_USE_AUTOCOMPLETE was added in https://github.com/ruby/irb/pull/469
|
||||
IRB.conf[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "false") == "true"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ feature_category: vulnerability_management
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177993
|
||||
milestone: '17.11'
|
||||
queued_migration_version: 20250404035239
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: 20250422130050
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillArchivedAndTraversalIdsToVulnerabilityStatistics < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_sec
|
||||
|
||||
MIGRATION_NAME = "BackfillArchivedAndTraversalIdsToVulnerabilityStatistics"
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: MIGRATION_NAME,
|
||||
table_name: :vulnerability_statistics,
|
||||
column_name: :id,
|
||||
job_arguments: []
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f4023de9e67c216e18bf1a89e1b39383ed086cc5e77335222bdb3c69e396ae9c
|
||||
|
|
@ -18,6 +18,8 @@ Prerequisites:
|
|||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133015) in GitLab 16.7 [with a flag](../administration/feature_flags.md) named `access_rest_chat`. Disabled by default. This feature is internal-only.
|
||||
- [Added additional_context parameter](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162650) in GitLab 17.4 [with a flag](../administration/feature_flags.md) named `duo_additional_context`. Disabled by default. This feature is internal-only.
|
||||
- [Enabled on GitLab.com and GitLab Self-Managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181305) in GitLab 17.9 [with a flag](../administration/feature_flags.md) named `duo_additional_context`.
|
||||
- [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/514559) in GitLab 18.0. Feature flag `duo_additional_context` removed in GitLab 18.0.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -13774,6 +13774,28 @@ paths:
|
|||
tags:
|
||||
- composer_packages
|
||||
operationId: getApiV4ProjectsIdPackagesComposerArchives*packageName
|
||||
"/api/v4/projects/{id}/packages/conan/v1/users/authenticate":
|
||||
get:
|
||||
summary: Authenticate user against conan CLI
|
||||
description: This feature was introduced in GitLab 12.2
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
description: The ID or URL-encoded path of the project
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticate user against conan CLI
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4ProjectsIdPackagesConanV1UsersAuthenticate
|
||||
"/api/v4/projects/{id}/packages/conan/v1/users/check_credentials":
|
||||
get:
|
||||
summary: Check for valid user credentials per conan CLI
|
||||
|
|
@ -13844,28 +13866,6 @@ paths:
|
|||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4ProjectsIdPackagesConanV1Ping
|
||||
"/api/v4/projects/{id}/packages/conan/v1/users/authenticate":
|
||||
get:
|
||||
summary: Authenticate user against conan CLI
|
||||
description: This feature was introduced in GitLab 12.2
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
description: The ID or URL-encoded path of the project
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticate user against conan CLI
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4ProjectsIdPackagesConanV1UsersAuthenticate
|
||||
? "/api/v4/projects/{id}/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}"
|
||||
: get:
|
||||
summary: Package Snapshot
|
||||
|
|
@ -14801,6 +14801,28 @@ paths:
|
|||
tags:
|
||||
- conan_packages
|
||||
operationId: putApiV4ProjectsIdPackagesConanV1FilesPackageNamePackageVersionPackageUsernamePackageChannelRecipeRevisionPackageConanPackageReferencePackageRevisionFileNameAuthorize
|
||||
"/api/v4/projects/{id}/packages/conan/v2/users/authenticate":
|
||||
get:
|
||||
summary: Authenticate user against conan CLI
|
||||
description: This feature was introduced in GitLab 12.2
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
description: The ID or URL-encoded path of the project
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticate user against conan CLI
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4ProjectsIdPackagesConanV2UsersAuthenticate
|
||||
"/api/v4/projects/{id}/packages/conan/v2/users/check_credentials":
|
||||
get:
|
||||
summary: Check for valid user credentials per conan CLI
|
||||
|
|
@ -38191,6 +38213,22 @@ paths:
|
|||
tags:
|
||||
- composer_packages
|
||||
operationId: getApiV4GroupIdPackagesComposer*packageName
|
||||
"/api/v4/packages/conan/v1/users/authenticate":
|
||||
get:
|
||||
summary: Authenticate user against conan CLI
|
||||
description: This feature was introduced in GitLab 12.2
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticate user against conan CLI
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4PackagesConanV1UsersAuthenticate
|
||||
"/api/v4/packages/conan/v1/users/check_credentials":
|
||||
get:
|
||||
summary: Check for valid user credentials per conan CLI
|
||||
|
|
@ -38244,22 +38282,6 @@ paths:
|
|||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4PackagesConanV1Ping
|
||||
"/api/v4/packages/conan/v1/users/authenticate":
|
||||
get:
|
||||
summary: Authenticate user against conan CLI
|
||||
description: This feature was introduced in GitLab 12.2
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'200':
|
||||
description: Authenticate user against conan CLI
|
||||
'401':
|
||||
description: Unauthorized
|
||||
'404':
|
||||
description: Not Found
|
||||
tags:
|
||||
- conan_packages
|
||||
operationId: getApiV4PackagesConanV1UsersAuthenticate
|
||||
? "/api/v4/packages/conan/v1/conans/{package_name}/{package_version}/{package_username}/{package_channel}/packages/{conan_package_reference}"
|
||||
: get:
|
||||
summary: Package Snapshot
|
||||
|
|
|
|||
|
|
@ -46,7 +46,41 @@ These endpoints all return `404 Not Found`.
|
|||
|
||||
## Create an authentication token
|
||||
|
||||
Creates a JSON Web Token (JWT) for use as a Bearer header in other requests using the Conan v1 [`/authenticate`](conan_v1.md#create-an-authentication-token) endpoint.
|
||||
Creates a JSON Web Token (JWT) for use as a Bearer header in other requests.
|
||||
|
||||
```shell
|
||||
"Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
The Conan 2 package manager client automatically uses this token.
|
||||
|
||||
```plaintext
|
||||
GET /projects/:id/packages/conan/v2/users/authenticate
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------ | ------------- | ---------------------------------------------------------------------------- |
|
||||
| `id` | string | Conditionally | The project ID or full project path. Required only for the project endpoint. |
|
||||
|
||||
Generate a base64-encoded Basic Auth token:
|
||||
|
||||
```shell
|
||||
echo -n "<username>:<personal_access_token>"|base64
|
||||
```
|
||||
|
||||
Use the base64-encoded Basic Auth token to get a JWT token:
|
||||
|
||||
```shell
|
||||
curl --request GET \
|
||||
--header 'Authorization: Basic <base64-encoded-token>' \
|
||||
--url "https://gitlab.example.com/api/v4/packages/conan/v2/users/authenticate"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```shell
|
||||
eyJhbGciOiJIUzI1NiIiheR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdG9rZW4iOjMyMTQyMzAsqaVzZXJfaWQiOjQwNTkyNTQsImp0aSI6IjdlNzBiZTNjLWFlNWQtNDEyOC1hMmIyLWZiOThhZWM0MWM2OSIsImlhd3r1MTYxNjYyMzQzNSwibmJmIjoxNjE2NjIzNDMwLCJleHAiOjE2MTY2MjcwMzV9.QF0Q3ZIB2GW5zNKyMSIe0HIFOITjEsZEioR-27Rtu7E
|
||||
```
|
||||
|
||||
## Verify authentication credentials
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ The following endpoints are available for CI/CD job tokens.
|
|||
| None | | `GET /projects/:id/packages/conan/v1/users/authenticate` | Authenticate user against conan CLI |
|
||||
| None | | `GET /projects/:id/packages/conan/v1/users/check_credentials` | Check for valid user credentials per conan CLI |
|
||||
| None | | `GET /projects/:id/packages/conan/v2/conans/search` | Search for packages |
|
||||
| None | | `GET /projects/:id/packages/conan/v2/users/authenticate` | Authenticate user against conan CLI |
|
||||
| None | | `GET /projects/:id/packages/conan/v2/users/check_credentials` | Check for valid user credentials per conan CLI |
|
||||
| None | | `GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name` | Get details about a repository tag |
|
||||
| None | | `GET /projects/:id/registry/repositories/:repository_id/tags` | List tags of a repository |
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ To view metrics on the Overview panel, the [background aggregation](#enable-or-d
|
|||
{{< history >}}
|
||||
|
||||
- Contributor count metric at the group level [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/433353) to GitLab.com in GitLab 16.9.
|
||||
- Contributor count metric at the project level [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/474119) to GitLab.com in GitLab 18.0.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
@ -275,6 +276,7 @@ Prerequisites:
|
|||
|
||||
- You must have at least the Reporter role for the project.
|
||||
- Overview background aggregation for Value Streams Dashboards must be enabled.
|
||||
- To view the contributor count metric in the comparison panel, you must [set up ClickHouse](../../integration/clickhouse.md).
|
||||
|
||||
To view the Value Streams Dashboard as an analytics dashboard for a project:
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ In addition, Chat is aware of different information, depending on where you use
|
|||
| Selected lines in editor | Selected code | {{< icon name="check-circle-filled" >}} Yes | {{< icon name="check-circle-filled" >}} Yes | With the lines selected, ask about `this code` or `this file`. Chat is not aware of the file; you must select the lines you want to ask about. |
|
||||
| Epics | Epic details | {{< icon name="dash-circle" >}} No | {{< icon name="check-circle-filled" >}} Yes | Ask about the URL. |
|
||||
| Issues | Issue details | {{< icon name="dash-circle" >}} No | {{< icon name="check-circle-filled" >}} Yes | Ask about the URL. |
|
||||
| Files | File content | {{< icon name="dash-circle" >}} No | {{< icon name="check-circle-filled" >}} Yes | Use the `/include` command to search for project files to add to Duo Chat's context. After you've added the files, you can ask Duo Chat questions about the file contents. Available for VS Code and JetBrains IDEs. For more information, see [Ask about specific files](examples.md#ask-about-specific-files-in-the-ide). |
|
||||
| Files | File content | {{< icon name="check-circle-filled" >}} Yes | {{< icon name="check-circle-filled" >}} Yes | Use the `/include` command to search for project files to add to Duo Chat's context. After you've added the files, you can ask Duo Chat questions about the file contents. Available for VS Code and JetBrains IDEs. For more information, see [Ask about specific files](examples.md#ask-about-specific-files-in-the-ide). |
|
||||
|
||||
In addition, in the IDEs, when you use any of the slash commands,
|
||||
like `/explain`, `/refactor`, `/fix`, or `/tests,` Duo Chat has access to the
|
||||
|
|
|
|||
|
|
@ -346,8 +346,7 @@ Programming languages that require compiling the source code may throw cryptic e
|
|||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/477258) in GitLab 17.7 [with flags](../../administration/feature_flags.md) named `duo_additional_context` and `duo_include_context_file`. Disabled by default.
|
||||
- [Enabled](https://gitlab.com/groups/gitlab-org/-/epics/15227) for [self-hosted model configuration](../../administration/gitlab_duo_self_hosted/_index.md#self-hosted-ai-gateway-and-llms) as well as the [default GitLab external AI vendor configuration](../../administration/gitlab_duo_self_hosted/_index.md#gitlabcom-ai-gateway-with-default-gitlab-external-vendor-llms) in GitLab 17.9.
|
||||
- [Enabled on GitLab.com, GitLab Self-Managed, and GitLab Dedicated](https://gitlab.com/groups/gitlab-org/-/epics/15183) in GitLab 17.9.
|
||||
- `duo_additional_context` flag [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/508741) in GitLab 17.10.
|
||||
- [Enabled on GitLab.com and GitLab Self-Managed](https://gitlab.com/groups/gitlab-org/-/epics/15183) in GitLab 17.9.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import localRules from 'eslint-plugin-local-rules';
|
|||
import js from '@eslint/js';
|
||||
import { FlatCompat } from '@eslint/eslintrc';
|
||||
import * as graphqlEslint from '@graphql-eslint/eslint-plugin';
|
||||
import * as todoLists from './.eslint_todo/index.mjs'
|
||||
import * as todoLists from './.eslint_todo/index.mjs';
|
||||
|
||||
const { dirname } = import.meta;
|
||||
const compat = new FlatCompat({
|
||||
|
|
@ -69,6 +69,27 @@ const jestConfig = {
|
|||
},
|
||||
};
|
||||
|
||||
/** An object to make it easier to reuse restricted imports */
|
||||
const restrictedImports = {
|
||||
axios: {
|
||||
name: 'axios',
|
||||
message: 'Import axios from ~/lib/utils/axios_utils instead.',
|
||||
},
|
||||
mousetrap: {
|
||||
name: 'mousetrap',
|
||||
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.',
|
||||
},
|
||||
sentry: {
|
||||
name: '@sentry/browser',
|
||||
message: 'Use "import * as Sentry from \'~/sentry/sentry_browser_wrapper\';" instead',
|
||||
},
|
||||
vuex: {
|
||||
name: 'vuex',
|
||||
message:
|
||||
'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.',
|
||||
},
|
||||
};
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
|
|
@ -341,19 +362,10 @@ export default [
|
|||
'error',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: 'mousetrap',
|
||||
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.',
|
||||
},
|
||||
{
|
||||
name: 'vuex',
|
||||
message:
|
||||
'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.',
|
||||
},
|
||||
{
|
||||
name: '@sentry/browser',
|
||||
message: 'Use "import * as Sentry from \'~/sentry/sentry_browser_wrapper\';" instead',
|
||||
},
|
||||
restrictedImports.axios,
|
||||
restrictedImports.mousetrap,
|
||||
restrictedImports.sentry,
|
||||
restrictedImports.vuex,
|
||||
],
|
||||
|
||||
patterns: [
|
||||
|
|
@ -522,19 +534,10 @@ export default [
|
|||
'error',
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: 'mousetrap',
|
||||
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.',
|
||||
},
|
||||
{
|
||||
name: 'vuex',
|
||||
message:
|
||||
'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.',
|
||||
},
|
||||
{
|
||||
name: '@sentry/browser',
|
||||
message: 'Use "import * as Sentry from \'~/sentry/sentry_browser_wrapper\';" instead',
|
||||
},
|
||||
restrictedImports.axios,
|
||||
restrictedImports.mousetrap,
|
||||
restrictedImports.sentry,
|
||||
restrictedImports.vuex,
|
||||
{
|
||||
name: '~/locale',
|
||||
importNames: ['__', 's__'],
|
||||
|
|
@ -703,7 +706,17 @@ export default [
|
|||
},
|
||||
},
|
||||
|
||||
// Consumer specs config
|
||||
/*
|
||||
contracts specs are a little different, as they are not "normal" jest specs.
|
||||
|
||||
They are actually executing `jest` and e.g. do proper non-mocked calls with axios in order
|
||||
to check API contracts.
|
||||
|
||||
They also do not directly execute library code, so some of our usual linting rules for app code
|
||||
like no-restricted-imports or i18n rules make no sense here and we can disable them.
|
||||
|
||||
For reference: https://docs.gitlab.com/development/testing_guide/contract/
|
||||
*/
|
||||
{
|
||||
files: ['{,ee/}spec/contracts/consumer/**/*.js'],
|
||||
|
||||
|
|
@ -713,6 +726,7 @@ export default [
|
|||
|
||||
rules: {
|
||||
'@gitlab/require-i18n-strings': 'off',
|
||||
'no-restricted-imports': 'off',
|
||||
},
|
||||
},
|
||||
...jhConfigs,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,25 @@ module API
|
|||
format :txt
|
||||
content_type :txt, 'text/plain'
|
||||
|
||||
desc 'Authenticate user against conan CLI' do
|
||||
detail 'This feature was introduced in GitLab 12.2'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[conan_packages]
|
||||
end
|
||||
|
||||
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
||||
route_setting :authorization, skip_job_token_policies: true
|
||||
|
||||
get 'authenticate', urgency: :low do
|
||||
unauthorized! unless token
|
||||
|
||||
token.to_jwt
|
||||
end
|
||||
|
||||
desc 'Check for valid user credentials per conan CLI' do
|
||||
detail 'This feature was introduced in GitLab 12.4'
|
||||
success code: 200
|
||||
|
|
|
|||
|
|
@ -41,34 +41,6 @@ module API
|
|||
header 'X-Conan-Server-Capabilities', x_conan_server_capabilities_header.join(',')
|
||||
end
|
||||
|
||||
namespace 'users' do
|
||||
before do
|
||||
authenticate!
|
||||
end
|
||||
|
||||
format :txt
|
||||
content_type :txt, 'text/plain'
|
||||
|
||||
desc 'Authenticate user against conan CLI' do
|
||||
detail 'This feature was introduced in GitLab 12.2'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 404, message: 'Not Found' }
|
||||
]
|
||||
tags %w[conan_packages]
|
||||
end
|
||||
|
||||
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
|
||||
route_setting :authorization, skip_job_token_policies: true
|
||||
|
||||
get 'authenticate', urgency: :low do
|
||||
unauthorized! unless token
|
||||
|
||||
token.to_jwt
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
requires :package_name, type: String, regexp: SharedEndpoints::PACKAGE_COMPONENT_REGEX,
|
||||
desc: 'Package name', documentation: { example: 'my-package' }
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ module Gitlab
|
|||
track_struct_event(tracker, category, action, label: label, property: property, value: value, contexts: contexts)
|
||||
end
|
||||
|
||||
def options(group)
|
||||
tracker.options(group)
|
||||
def frontend_client_options(group)
|
||||
tracker.frontend_client_options(group)
|
||||
end
|
||||
|
||||
def collector_hostname
|
||||
|
|
|
|||
|
|
@ -40,16 +40,18 @@ module Gitlab
|
|||
emitter.input(payload)
|
||||
end
|
||||
|
||||
def options(group)
|
||||
def frontend_client_options(group)
|
||||
additional_features = Feature.enabled?(:additional_snowplow_tracking, group, type: :ops)
|
||||
|
||||
# Using camel case as these keys will be used only in JavaScript
|
||||
{
|
||||
namespace: SNOWPLOW_NAMESPACE,
|
||||
hostname: hostname,
|
||||
cookie_domain: cookie_domain,
|
||||
app_id: app_id,
|
||||
form_tracking: additional_features,
|
||||
link_click_tracking: additional_features
|
||||
}.transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
|
||||
cookieDomain: cookie_domain,
|
||||
appId: app_id,
|
||||
formTracking: additional_features,
|
||||
linkClickTracking: additional_features
|
||||
}
|
||||
end
|
||||
|
||||
def enabled?
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ module Gitlab
|
|||
|
||||
DEFAULT_URI = 'http://localhost:9090'
|
||||
|
||||
override :options
|
||||
def options(group)
|
||||
super.update(
|
||||
override :frontend_client_options
|
||||
def frontend_client_options(group)
|
||||
super.merge(
|
||||
protocol: uri.scheme,
|
||||
port: uri.port,
|
||||
force_secure_tracker: false
|
||||
).transform_keys! { |key| key.to_s.camelize(:lower).to_sym }
|
||||
forceSecureTracker: false # Using camel case as this key will be used only in JavaScript
|
||||
)
|
||||
end
|
||||
|
||||
override :enabled?
|
||||
|
|
|
|||
|
|
@ -5732,6 +5732,9 @@ msgstr ""
|
|||
msgid "AiPowered|Enable AI logs"
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|Enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|Enabling self-hosted beta models and features is your acceptance of the %{linkStart}GitLab Testing Agreement%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -5765,6 +5768,9 @@ msgstr ""
|
|||
msgid "AiPowered|GitLab Duo Chat conversation expiration"
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|GitLab Duo Core available to all users"
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|GitLab Duo Self-Hosted"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -5792,6 +5798,9 @@ msgstr ""
|
|||
msgid "AiPowered|Monitor, manage, and customize AI features to ensure efficient utilization and alignment."
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|Not enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "AiPowered|Off by default"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37044,6 +37053,9 @@ msgstr ""
|
|||
msgid "MemberRole|Are you sure you want to delete this role?"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Automatically sync your LDAP directory to custom admin roles."
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Base role"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37059,6 +37071,9 @@ msgstr ""
|
|||
msgid "MemberRole|Could not fetch available permissions."
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Could not load LDAP synchronizations. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Could not update role."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37080,6 +37095,9 @@ msgstr ""
|
|||
msgid "MemberRole|Custom admin role"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Custom admin role:"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Custom member role"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37158,6 +37176,9 @@ msgstr ""
|
|||
msgid "MemberRole|Failed to save role: %{error}"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Group cn:"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Learn more about %{linkStart}available custom permissions%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37182,6 +37203,9 @@ msgstr ""
|
|||
msgid "MemberRole|New role"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|No active LDAP synchronizations. Add synchronization to connect your LDAP directory with custom admin roles."
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|No description"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37191,6 +37215,9 @@ msgstr ""
|
|||
msgid "MemberRole|Permission"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Remove sync"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Reverted to LDAP group sync settings. The role will be updated after the next LDAP sync."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37239,6 +37266,12 @@ msgstr ""
|
|||
msgid "MemberRole|Select at least one permission."
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Server:"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|Sync all"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|The CSV report contains a list of users, assigned role and access in all groups, subgroups, and projects. When the export is completed, it will be sent as an attachment to %{email}."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -37293,6 +37326,12 @@ msgstr ""
|
|||
msgid "MemberRole|Use LDAP sync role"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|User filter:"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|View LDAP synced users"
|
||||
msgstr ""
|
||||
|
||||
msgid "MemberRole|View permissions"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -49594,7 +49633,7 @@ msgstr ""
|
|||
msgid "Rate the review"
|
||||
msgstr ""
|
||||
|
||||
msgid "Rate this response %{separator} %{codeStart}%{botUser}%{codeEnd} in reply for more questions"
|
||||
msgid "Rate this response %{separator} Mention %{codeStart}%{botUser}%{codeEnd} to continue the conversation."
|
||||
msgstr ""
|
||||
|
||||
msgid "Raw blob request rate limit per minute"
|
||||
|
|
@ -66193,7 +66232,7 @@ msgstr ""
|
|||
msgid "ValueStreamAnalytics|Number of merge requests merged by month."
|
||||
msgstr ""
|
||||
|
||||
msgid "ValueStreamAnalytics|Number of monthly unique users with contributions in the group."
|
||||
msgid "ValueStreamAnalytics|Number of monthly unique users with contributions."
|
||||
msgstr ""
|
||||
|
||||
msgid "ValueStreamAnalytics|Number of new issues created."
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ ee/spec/frontend/requirements/components/requirement_item_spec.js
|
|||
ee/spec/frontend/requirements/components/requirements_root_spec.js
|
||||
ee/spec/frontend/roadmap/components/roadmap_shell_spec.js
|
||||
ee/spec/frontend/roles_and_permissions/components/role_selector_spec.js
|
||||
ee/spec/frontend/security_configuration/components/app_spec.js
|
||||
ee/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
|
||||
ee/spec/frontend/status_checks/components/modal_create_spec.js
|
||||
ee/spec/frontend/status_checks/mount_spec.js
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlPagination, GlTable } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import InactiveAccessTokenTableApp from '~/access_tokens/components/inactive_access_token_table_app.vue';
|
||||
import { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import * as actions from '~/admin/statistics_panel/store/actions';
|
||||
import * as types from '~/admin/statistics_panel/store/mutation_types';
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import {
|
|||
GlLink,
|
||||
} from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import mockAlerts from 'jest/vue_shared/alert_details/mocks/alerts.json';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
filterMilestones,
|
||||
filterLabels,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import * as actions from '~/analytics/cycle_analytics/store/actions';
|
||||
import * as getters from '~/analytics/cycle_analytics/store/getters';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { GlAlert, GlLink, GlSprintf, GlLoadingIcon } from '@gitlab/ui';
|
|||
import { EditorContent, Editor } from '@tiptap/vue-2';
|
||||
import { nextTick } from 'vue';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { CONTENT_EDITOR_PASTE } from '~/vue_shared/constants';
|
||||
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import fs from 'fs';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { builders } from 'prosemirror-test-builder';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import Attachment from '~/content_editor/extensions/attachment';
|
||||
import DrawioDiagram from '~/content_editor/extensions/drawio_diagram';
|
||||
import Image from '~/content_editor/extensions/image';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import AutocompleteHelper, {
|
||||
defaultSorter,
|
||||
customSorter,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { uploadFile } from '~/content_editor/services/upload_helpers';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import getIdeProject from 'ee_else_ce/ide/queries/get_ide_project.query.graphql';
|
||||
import Api from '~/api';
|
||||
import services from '~/ide/services';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { file } from 'jest/ide/helpers';
|
||||
import { commitActionTypes, PERMISSION_CREATE_MR } from '~/ide/constants';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlAlert, GlForm } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { setHTMLFixture } from 'helpers/fixtures';
|
||||
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/constants';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { nextTick } from 'vue';
|
||||
import { GlAvatarLabeled, GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { getGroups } from '~/api/groups_api';
|
||||
import { getProjectShareLocations } from '~/api/projects_api';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlModal, GlSprintf, GlFormInputGroup, GlButton } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
/*
|
||||
We need to import axios directly here, the shared lib already applies
|
||||
the interceptor we are trying to test.
|
||||
*/
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import setupAxiosStartupCalls from '~/lib/utils/axios_startup_calls';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { noop } from 'lodash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { useFakeDate } from 'helpers/fake_date';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { members, group, modalData } from 'jest/members/mock_data';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import Cookies from '~/lib/utils/cookies';
|
||||
import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { GlLoadingIcon, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import Vue from 'vue';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import MilestoneCombobox from '~/milestones/components/milestone_combobox.vue';
|
||||
import createStore from '~/milestones/stores/';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { uploadModel } from '~/ml/model_registry/services/upload_model';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
||||
|
|
|
|||
|
|
@ -338,8 +338,9 @@ describe('issue_note_body component', () => {
|
|||
|
||||
const result = wrapper.vm.duoFeedbackText;
|
||||
expect(result).toContain('Rate this response');
|
||||
expect(result).toContain('Mention');
|
||||
expect(result).toContain('@GitLabDuo');
|
||||
expect(result).toContain('in reply for more questions');
|
||||
expect(result).toContain('to continue the conversation.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlSprintf, GlModal, GlFormGroup, GlFormCheckbox, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GlButton, GlButtonGroup, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import Api from '~/api';
|
||||
import { createAlert } from '~/alert';
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import {
|
|||
GlFormRadio,
|
||||
GlSprintf,
|
||||
} from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import { kebabCase, merge } from 'lodash';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { createAlert } from '~/alert';
|
||||
import * as urlUtility from '~/lib/utils/url_utility';
|
||||
import ForkForm from '~/pages/projects/forks/new/components/fork_form.vue';
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import {
|
|||
GlFormCheckbox,
|
||||
} from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mockTracking } from 'helpers/tracking_helper';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import WikiForm from '~/pages/shared/wikis/components/wiki_form.vue';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { createAlert } from '~/alert';
|
||||
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from 'axios';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { resetHTMLFixture, setHTMLFixture } from 'helpers/fixtures';
|
||||
import { initFileBrowser } from '~/rapid_diffs/app/init_file_browser';
|
||||
import createEventHub from '~/helpers/event_hub_factory';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { GlLoadingIcon, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { merge, last } from 'lodash';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
|
|
@ -10,6 +9,7 @@ import commit from 'test_fixtures/api/commits/commit.json';
|
|||
import branches from 'test_fixtures/api/branches/branches.json';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import {
|
||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||
HTTP_STATUS_NOT_FOUND,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { merge } from 'lodash';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
|
|
@ -6,6 +5,7 @@ import Vuex from 'vuex';
|
|||
import { nextTick } from 'vue';
|
||||
import { GlDatepicker, GlFormCheckbox } from '@gitlab/ui';
|
||||
import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import createMilestoneComboboxState from '~/milestones/stores/state';
|
||||
import { convertOneReleaseGraphQLResponse } from '~/releases/util';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlButton, GlFormInput, GlFormTextarea } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import TagCreate from '~/releases/components/tag_create.vue';
|
||||
import RefSelector from '~/ref/components/ref_selector.vue';
|
||||
import createStore from '~/releases/stores';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GlFormGroup, GlTruncate, GlPopover } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import TagFieldNew from '~/releases/components/tag_field_new.vue';
|
||||
import TagSearch from '~/releases/components/tag_search.vue';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlButton, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { DEFAULT_PER_PAGE } from '~/api';
|
||||
import { sprintf } from '~/locale';
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { mount, shallowMount } from '@vue/test-utils';
|
|||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert } from '~/alert';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import DeleteBlobModal from '~/repository/components/delete_blob_modal.vue';
|
||||
import CommitChangesModal from '~/repository/components/commit_changes_modal.vue';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { HTTP_STATUS_OK, HTTP_STATUS_UNPROCESSABLE_ENTITY } from '~/lib/utils/http_status';
|
||||
import * as urlUtility from '~/lib/utils/url_utility';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import FileIcon from '~/vue_shared/components/file_icon.vue';
|
||||
import { createAlert } from '~/alert';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { splitIntoChunks } from '~/vue_shared/components/source_viewer/workers/highlight_utils';
|
||||
import highlightMixin from '~/repository/mixins/highlight_mixin';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GlForm, GlFormInput } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { createAlert, VARIANT_SUCCESS } from '~/alert';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { createAlert, VARIANT_SUCCESS } from '~/alert';
|
||||
import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import Vue, { nextTick } from 'vue';
|
||||
import axios from 'axios';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { PiniaVuePlugin } from 'pinia';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { useMockInternalEventsTracking } from 'helpers/tracking_internal_events_helper';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import axios from 'axios';
|
||||
import { GlLoadingIcon, GlSprintf } from '@gitlab/ui';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import MemoryUsage from '~/vue_merge_request_widget/components/deployment/memory_usage.vue';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import Vue, { nextTick } from 'vue';
|
|||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import Vue, { nextTick } from 'vue';
|
|||
import VueApollo from 'vue-apollo';
|
||||
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import AlertSidebar from '~/vue_shared/alert_details/components/alert_sidebar.vue';
|
||||
import SidebarAssignees from '~/vue_shared/alert_details/components/sidebar/sidebar_assignees.vue';
|
||||
import SidebarStatus from '~/vue_shared/alert_details/components/sidebar/sidebar_status.vue';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import Vue from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { GlAvatar, GlDropdownItem } from '@gitlab/ui';
|
||||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import SidebarAssignee from '~/vue_shared/alert_details/components/sidebar/sidebar_assignee.vue';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { mockBranches } from 'jest/vue_shared/components/filtered_search_bar/mock_data';
|
||||
import Api from '~/api';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import axios from 'axios';
|
||||
import Autosize from 'autosize';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import {
|
||||
EDITING_MODE_MARKDOWN_FIELD,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,24 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import App from '~/work_items/components/app.vue';
|
||||
import { ROUTES } from '~/work_items/constants';
|
||||
|
||||
describe('Work Items Application', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = () => {
|
||||
const DEFAULT_ROUTE_MOCK = {
|
||||
path: '/',
|
||||
name: ROUTES.index,
|
||||
params: {},
|
||||
};
|
||||
|
||||
const createComponent = (routeMock = DEFAULT_ROUTE_MOCK) => {
|
||||
wrapper = shallowMount(App, {
|
||||
stubs: {
|
||||
'router-view': true,
|
||||
},
|
||||
mocks: {
|
||||
$route: routeMock,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import * as autosave from '~/lib/utils/autosave';
|
|||
import { ESC_KEY, ENTER_KEY } from '~/lib/utils/keys';
|
||||
import { STATE_OPEN, i18n } from '~/work_items/constants';
|
||||
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
|
||||
import gfmEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import HelpIcon from '~/vue_shared/components/help_icon/help_icon.vue';
|
||||
import workItemEmailParticipantsByIidQuery from '~/work_items/graphql/notes/work_item_email_participants_by_iid.query.graphql';
|
||||
import * as confirmViaGlModal from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
|
||||
|
|
@ -299,6 +300,19 @@ describe('Work item comment form component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('emits edit-current-user-last-note on `up` keypress', async () => {
|
||||
await createComponent();
|
||||
|
||||
jest.spyOn(gfmEventHub, '$emit').mockImplementation(jest.fn());
|
||||
|
||||
findMarkdownEditor().vm.$emit('keydown', new KeyboardEvent('keydown', { key: 'ArrowUp' }));
|
||||
|
||||
expect(gfmEventHub.$emit).toHaveBeenCalledWith(
|
||||
'edit-current-user-last-note',
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
it('cancels editing on clicking cancel button', async () => {
|
||||
createComponent();
|
||||
findCancelButton().vm.$emit('click');
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Vue, { nextTick } from 'vue';
|
|||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import gfmEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
|
||||
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
|
||||
import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
|
||||
|
|
@ -29,6 +30,7 @@ describe('Work Item Discussion', () => {
|
|||
|
||||
const findToggleRepliesWidget = () => wrapper.findComponent(ToggleRepliesWidget);
|
||||
const findAllThreads = () => wrapper.findAllComponents(WorkItemNote);
|
||||
const findTimelineEntryItem = () => wrapper.findComponent(TimelineEntryItem);
|
||||
const findThreadAtIndex = (index) => findAllThreads().at(index);
|
||||
const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
|
||||
const findWorkItemNoteReplying = () => wrapper.findComponent(WorkItemNoteReplying);
|
||||
|
|
@ -102,6 +104,17 @@ describe('Work Item Discussion', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should render timeline-entry-item with required data attributes', () => {
|
||||
const expectedDiscussion =
|
||||
mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[0].notes.nodes[0];
|
||||
|
||||
expect(findTimelineEntryItem().attributes()).toEqual({
|
||||
class: expect.any(String),
|
||||
'data-note-id': expectedDiscussion.id.split('/').pop(),
|
||||
'data-discussion-id': expectedDiscussion.discussion.id,
|
||||
});
|
||||
});
|
||||
|
||||
it('should show the toggle replies widget', () => {
|
||||
expect(findToggleRepliesWidget().exists()).toBe(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mockApollo from 'helpers/mock_apollo_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { updateDraft, clearDraft } from '~/lib/utils/autosave';
|
||||
import EditedAt from '~/issues/show/components/edited.vue';
|
||||
import gfmEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||
import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
|
||||
import WorkItemNoteAwardsList from '~/work_items/components/notes/work_item_note_awards_list.vue';
|
||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
||||
|
|
@ -104,6 +105,7 @@ describe('Work Item Note', () => {
|
|||
isFirstNote,
|
||||
workItemType: 'Task',
|
||||
markdownPreviewPath: '/group/project/preview_markdown?target_type=WorkItem',
|
||||
uploadsPath: '/test-project-path/uploads',
|
||||
autocompleteDataSources: {},
|
||||
assignees,
|
||||
},
|
||||
|
|
@ -510,4 +512,41 @@ end`;
|
|||
expect(findNoteActions().props('showAssignUnassign')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('markdown-editor event-hub edit-note event', () => {
|
||||
const setupComponent = async ({ id = mockWorkItemCommentNote.id, adminNote = true } = {}) => {
|
||||
createComponent({
|
||||
note: {
|
||||
...mockWorkItemCommentNote,
|
||||
id,
|
||||
userPermissions: {
|
||||
...mockWorkItemCommentNote.userPermissions,
|
||||
adminNote,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
gfmEventHub.$emit('edit-note', { note: mockWorkItemCommentNote });
|
||||
|
||||
await nextTick();
|
||||
};
|
||||
|
||||
it('enables editing on the note for a matching note when adminNote is true', async () => {
|
||||
await setupComponent();
|
||||
|
||||
expect(wrapper.emitted('startEditing')).toHaveLength(1);
|
||||
expect(findCommentForm().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it.each`
|
||||
setupProps | description
|
||||
${{ adminNote: false }} | ${'a matching note when adminNote is false'}
|
||||
${{ id: 'gid://gitlab/Note/100' }} | ${'non-matching note when adminNote is true'}
|
||||
`('does not enable editing on the note for $description', async ({ setupProps }) => {
|
||||
await setupComponent(setupProps);
|
||||
|
||||
expect(wrapper.emitted('startEditing')).toBeUndefined();
|
||||
expect(findCommentForm().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import Vue, { nextTick } from 'vue';
|
||||
import { GlForm, GlModal } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import axios from 'axios';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ describe('WorkItemNotes component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('reply shortcut', () => {
|
||||
describe('r key (reply) shortcut', () => {
|
||||
const triggerReplyShortcut = async () => {
|
||||
Mousetrap.trigger(keysFor(ISSUABLE_COMMENT_OR_REPLY)[0]);
|
||||
await nextTick();
|
||||
|
|
@ -670,4 +670,77 @@ describe('WorkItemNotes component', () => {
|
|||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('up-arrow key (edit last note) shortcut', () => {
|
||||
const setupComponent = async ({
|
||||
notesResponse = mockWorkItemNotesResponseWithComments(),
|
||||
} = {}) => {
|
||||
window.gon.current_user_id = 1;
|
||||
|
||||
jest.clearAllMocks();
|
||||
|
||||
jest.spyOn(gfmEventHub, '$emit').mockImplementation(jest.fn());
|
||||
jest.spyOn(gfmEventHub, '$on').mockImplementation(jest.fn());
|
||||
|
||||
createComponent({
|
||||
defaultWorkItemNotesQueryHandler: jest.fn().mockResolvedValue(notesResponse),
|
||||
canCreateNote: true,
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
};
|
||||
|
||||
it('attaches `edit-current-user-last-note` event listener on mount', async () => {
|
||||
await setupComponent();
|
||||
|
||||
expect(gfmEventHub.$on).toHaveBeenCalledWith(
|
||||
'edit-current-user-last-note',
|
||||
wrapper.vm.editCurrentUserLastNote,
|
||||
);
|
||||
});
|
||||
|
||||
it('emits `edit-note` on markdown-editor event-hub with last user note', async () => {
|
||||
const mockLastNote =
|
||||
mockWorkItemNotesWidgetResponseWithComments.discussions.nodes[1].notes.nodes[0];
|
||||
await setupComponent();
|
||||
|
||||
const registeredHandler = gfmEventHub.$on.mock.calls.find(
|
||||
(call) => call[0] === 'edit-current-user-last-note',
|
||||
)[1];
|
||||
|
||||
const mockEvent = {
|
||||
target: wrapper.findComponent(WorkItemAddNote).element,
|
||||
};
|
||||
|
||||
await registeredHandler(mockEvent);
|
||||
|
||||
expect(gfmEventHub.$emit).toHaveBeenCalledWith('edit-note', {
|
||||
note: {
|
||||
...mockLastNote,
|
||||
discussion: {
|
||||
...mockLastNote.discussion,
|
||||
resolvable: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('does not emit `edit-note` on markdown-editor event-hub when no last user note is found', async () => {
|
||||
await setupComponent({
|
||||
notesResponse: mockWorkItemNotesByIidResponse,
|
||||
});
|
||||
|
||||
const registeredHandler = gfmEventHub.$on.mock.calls.find(
|
||||
(call) => call[0] === 'edit-current-user-last-note',
|
||||
)[1];
|
||||
|
||||
const mockEvent = {
|
||||
target: wrapper.findComponent(WorkItemAddNote).element,
|
||||
};
|
||||
|
||||
await registeredHandler(mockEvent);
|
||||
|
||||
expect(gfmEventHub.$emit).not.toHaveBeenCalledWith('edit-note');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import Dropzone from 'dropzone';
|
||||
import $ from 'jquery';
|
||||
|
|
@ -6,6 +5,7 @@ import htmlSnippetsShow from 'test_fixtures/snippets/show.html';
|
|||
import { Mousetrap } from '~/lib/mousetrap';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import GLForm from '~/gl_form';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import * as utils from '~/lib/utils/common_utils';
|
||||
import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
||||
import ZenMode from '~/zen_mode';
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ RSpec.describe Gitlab::Tracking::Destinations::SnowplowMicro, feature_category:
|
|||
end
|
||||
end
|
||||
|
||||
describe '#options' do
|
||||
describe '#frontend_client_options' do
|
||||
let_it_be(:group) { create :group }
|
||||
|
||||
before do
|
||||
|
|
@ -64,15 +64,15 @@ RSpec.describe Gitlab::Tracking::Destinations::SnowplowMicro, feature_category:
|
|||
end
|
||||
|
||||
it 'includes protocol with the correct value' do
|
||||
expect(subject.options(group)[:protocol]).to eq 'http'
|
||||
expect(subject.frontend_client_options(group)[:protocol]).to eq 'http'
|
||||
end
|
||||
|
||||
it 'includes port with the correct value' do
|
||||
expect(subject.options(group)[:port]).to eq 9091
|
||||
expect(subject.frontend_client_options(group)[:port]).to eq 9091
|
||||
end
|
||||
|
||||
it 'includes forceSecureTracker with value false' do
|
||||
expect(subject.options(group)[:forceSecureTracker]).to eq false
|
||||
expect(subject.frontend_client_options(group)[:forceSecureTracker]).to eq false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ RSpec.describe Gitlab::Tracking, feature_category: :application_instrumentation
|
|||
|
||||
it { is_expected.to delegate_method(:flush).to(:tracker) }
|
||||
|
||||
describe '.options' do
|
||||
describe '.frontend_client_options' do
|
||||
shared_examples 'delegates to destination' do |klass|
|
||||
before do
|
||||
allow_next_instance_of(klass) do |instance|
|
||||
allow(instance).to receive(:options).and_call_original
|
||||
allow(instance).to receive(:frontend_client_options).and_call_original
|
||||
end
|
||||
end
|
||||
|
||||
it "delegates to #{klass} destination" do
|
||||
expect_next_instance_of(klass) do |instance|
|
||||
expect(instance).to receive(:options)
|
||||
expect(instance).to receive(:frontend_client_options)
|
||||
end
|
||||
|
||||
subject.options(nil)
|
||||
subject.frontend_client_options(nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ RSpec.describe Gitlab::Tracking, feature_category: :application_instrumentation
|
|||
linkClickTracking: true
|
||||
}
|
||||
|
||||
expect(subject.options(nil)).to match(expected_fields)
|
||||
expect(subject.frontend_client_options(nil)).to match(expected_fields)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ RSpec.describe Gitlab::Tracking, feature_category: :application_instrumentation
|
|||
linkClickTracking: true
|
||||
}
|
||||
|
||||
expect(subject.options(nil)).to match(expected_fields)
|
||||
expect(subject.frontend_client_options(nil)).to match(expected_fields)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ RSpec.describe Gitlab::Tracking, feature_category: :application_instrumentation
|
|||
it 'when feature flag is disabled' do
|
||||
stub_feature_flags(additional_snowplow_tracking: false)
|
||||
|
||||
expect(subject.options(nil)).to include(
|
||||
expect(subject.frontend_client_options(nil)).to include(
|
||||
formTracking: false,
|
||||
linkClickTracking: false
|
||||
)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue