Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
477c2c2604
commit
6724a6ee6b
|
|
@ -687,9 +687,6 @@ Rails/SaveBang:
|
|||
- 'ee/spec/lib/gitlab/background_migration/fix_orphan_promoted_issues_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/elastic/search_results_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/email/handler/ee/service_desk_handler_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/cron_manager_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo/oauth/session_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/geo_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/git_access_spec.rb'
|
||||
- 'ee/spec/lib/gitlab/import_export/group/relation_factory_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import {
|
||||
GlButton,
|
||||
GlButtonGroup,
|
||||
|
|
@ -17,6 +18,7 @@ import boardsStore from '../stores/boards_store';
|
|||
import eventHub from '../eventhub';
|
||||
import { ListType } from '../constants';
|
||||
import { isScopedLabel } from '~/lib/utils/common_utils';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -32,7 +34,7 @@ export default {
|
|||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
},
|
||||
mixins: [isWipLimitsOn],
|
||||
mixins: [isWipLimitsOn, glFeatureFlagMixin()],
|
||||
props: {
|
||||
list: {
|
||||
type: Object,
|
||||
|
|
@ -128,6 +130,7 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['updateList']),
|
||||
showScopedLabels(label) {
|
||||
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
|
||||
},
|
||||
|
|
@ -136,20 +139,28 @@ export default {
|
|||
eventHub.$emit(`toggle-issue-form-${this.list.id}`);
|
||||
},
|
||||
toggleExpanded() {
|
||||
if (this.list.isExpandable) {
|
||||
this.list.isExpanded = !this.list.isExpanded;
|
||||
this.list.isExpanded = !this.list.isExpanded;
|
||||
|
||||
if (AccessorUtilities.isLocalStorageAccessSafe() && !this.isLoggedIn) {
|
||||
localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded);
|
||||
}
|
||||
if (!this.isLoggedIn) {
|
||||
this.addToLocalStorage();
|
||||
} else {
|
||||
this.updateListFunction();
|
||||
}
|
||||
|
||||
if (this.isLoggedIn) {
|
||||
this.list.update();
|
||||
}
|
||||
|
||||
// When expanding/collapsing, the tooltip on the caret button sometimes stays open.
|
||||
// Close all tooltips manually to prevent dangling tooltips.
|
||||
this.$root.$emit('bv::hide::tooltip');
|
||||
// When expanding/collapsing, the tooltip on the caret button sometimes stays open.
|
||||
// Close all tooltips manually to prevent dangling tooltips.
|
||||
this.$root.$emit('bv::hide::tooltip');
|
||||
},
|
||||
addToLocalStorage() {
|
||||
if (AccessorUtilities.isLocalStorageAccessSafe()) {
|
||||
localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded);
|
||||
}
|
||||
},
|
||||
updateListFunction() {
|
||||
if (this.glFeatures.boardsWithSwimlanes && this.isSwimlanesHeader) {
|
||||
this.updateList({ listId: this.list.id, collapsed: !this.list.isExpanded });
|
||||
} else {
|
||||
this.list.update();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class List {
|
|||
this.loading = true;
|
||||
this.loadingMore = false;
|
||||
this.issues = obj.issues || [];
|
||||
this.issuesSize = obj.issuesSize ? obj.issuesSize : 0;
|
||||
this.issuesSize = obj.issuesSize || obj.issuesCount || 0;
|
||||
this.maxIssueCount = obj.maxIssueCount || obj.max_issue_count || 0;
|
||||
|
||||
if (obj.label) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ fragment BoardListShared on BoardList {
|
|||
position
|
||||
listType
|
||||
collapsed
|
||||
issuesCount
|
||||
label {
|
||||
id
|
||||
title
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#import "./board_list.fragment.graphql"
|
||||
|
||||
mutation UpdateBoardList($listId: ID!, $position: Int, $collapsed: Boolean) {
|
||||
updateBoardList(input: { listId: $listId, position: $position, collapsed: $collapsed }) {
|
||||
list {
|
||||
...BoardListFragment
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import projectListsIssuesQuery from '../queries/project_lists_issues.query.graph
|
|||
import projectBoardQuery from '../queries/project_board.query.graphql';
|
||||
import groupBoardQuery from '../queries/group_board.query.graphql';
|
||||
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
|
||||
import updateBoardListMutation from '../queries/board_list_update.mutation.graphql';
|
||||
|
||||
const notImplemented = () => {
|
||||
/* eslint-disable-next-line @gitlab/require-i18n-strings */
|
||||
|
|
@ -147,8 +148,42 @@ export default {
|
|||
notImplemented();
|
||||
},
|
||||
|
||||
updateList: () => {
|
||||
notImplemented();
|
||||
moveList: ({ state, commit, dispatch }, { listId, newIndex, adjustmentValue }) => {
|
||||
const { boardLists } = state;
|
||||
const backupList = [...boardLists];
|
||||
const movedList = boardLists.find(({ id }) => id === listId);
|
||||
|
||||
const newPosition = newIndex - 1;
|
||||
const listAtNewIndex = boardLists[newIndex];
|
||||
|
||||
movedList.position = newPosition;
|
||||
listAtNewIndex.position += adjustmentValue;
|
||||
commit(types.MOVE_LIST, {
|
||||
movedList,
|
||||
listAtNewIndex,
|
||||
});
|
||||
|
||||
dispatch('updateList', { listId, position: newPosition, backupList });
|
||||
},
|
||||
|
||||
updateList: ({ commit }, { listId, position, collapsed, backupList }) => {
|
||||
gqlClient
|
||||
.mutate({
|
||||
mutation: updateBoardListMutation,
|
||||
variables: {
|
||||
listId,
|
||||
position,
|
||||
collapsed,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data?.updateBoardList?.errors.length) {
|
||||
commit(types.UPDATE_LIST_FAILURE, backupList);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
commit(types.UPDATE_LIST_FAILURE, backupList);
|
||||
});
|
||||
},
|
||||
|
||||
deleteList: () => {
|
||||
|
|
|
|||
|
|
@ -858,21 +858,6 @@ const boardsStore = {
|
|||
},
|
||||
|
||||
refreshIssueData(issue, obj) {
|
||||
// issue.id = obj.id;
|
||||
// issue.iid = obj.iid;
|
||||
// issue.title = obj.title;
|
||||
// issue.confidential = obj.confidential;
|
||||
// issue.dueDate = obj.due_date || obj.dueDate;
|
||||
// issue.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
|
||||
// issue.referencePath = obj.reference_path || obj.referencePath;
|
||||
// issue.path = obj.real_path || obj.webUrl;
|
||||
// issue.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
|
||||
// issue.project_id = obj.project_id;
|
||||
// issue.timeEstimate = obj.time_estimate || obj.timeEstimate;
|
||||
// issue.assignableLabelsEndpoint = obj.assignable_labels_endpoint;
|
||||
// issue.blocked = obj.blocked;
|
||||
// issue.epic = obj.epic;
|
||||
|
||||
const convertedObj = convertObjectPropsToCamelCase(obj, {
|
||||
dropKeys: ['issue_sidebar_endpoint', 'real_path', 'webUrl'],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ export const SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST';
|
|||
export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
|
||||
export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
|
||||
export const RECEIVE_ADD_LIST_ERROR = 'RECEIVE_ADD_LIST_ERROR';
|
||||
export const REQUEST_UPDATE_LIST = 'REQUEST_UPDATE_LIST';
|
||||
export const RECEIVE_UPDATE_LIST_SUCCESS = 'RECEIVE_UPDATE_LIST_SUCCESS';
|
||||
export const RECEIVE_UPDATE_LIST_ERROR = 'RECEIVE_UPDATE_LIST_ERROR';
|
||||
export const MOVE_LIST = 'MOVE_LIST';
|
||||
export const UPDATE_LIST_FAILURE = 'UPDATE_LIST_FAILURE';
|
||||
export const REQUEST_REMOVE_LIST = 'REQUEST_REMOVE_LIST';
|
||||
export const RECEIVE_REMOVE_LIST_SUCCESS = 'RECEIVE_REMOVE_LIST_SUCCESS';
|
||||
export const RECEIVE_REMOVE_LIST_ERROR = 'RECEIVE_REMOVE_LIST_ERROR';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import { sortBy } from 'lodash';
|
||||
import * as mutationTypes from './mutation_types';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
|
|
@ -44,16 +46,17 @@ export default {
|
|||
notImplemented();
|
||||
},
|
||||
|
||||
[mutationTypes.REQUEST_UPDATE_LIST]: () => {
|
||||
notImplemented();
|
||||
[mutationTypes.MOVE_LIST]: (state, { movedList, listAtNewIndex }) => {
|
||||
const { boardLists } = state;
|
||||
const movedListIndex = state.boardLists.findIndex(l => l.id === movedList.id);
|
||||
Vue.set(boardLists, movedListIndex, movedList);
|
||||
Vue.set(boardLists, movedListIndex.position + 1, listAtNewIndex);
|
||||
Vue.set(state, 'boardLists', sortBy(boardLists, 'position'));
|
||||
},
|
||||
|
||||
[mutationTypes.RECEIVE_UPDATE_LIST_SUCCESS]: () => {
|
||||
notImplemented();
|
||||
},
|
||||
|
||||
[mutationTypes.RECEIVE_UPDATE_LIST_ERROR]: () => {
|
||||
notImplemented();
|
||||
[mutationTypes.UPDATE_LIST_FAILURE]: (state, backupList) => {
|
||||
state.error = __('An error occurred while updating the list. Please try again.');
|
||||
Vue.set(state, 'boardLists', backupList);
|
||||
},
|
||||
|
||||
[mutationTypes.REQUEST_REMOVE_LIST]: () => {
|
||||
|
|
|
|||
|
|
@ -14,3 +14,40 @@ export const serializeForm = form => {
|
|||
|
||||
return serializeFormEntries(entries);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the value provided is empty or not
|
||||
*
|
||||
* It is being used to check if a form input
|
||||
* value has been set or not
|
||||
*
|
||||
* @param {String, Number, Array} - Any form value
|
||||
* @returns {Boolean} - returns false if a value is set
|
||||
*
|
||||
* @example
|
||||
* returns true for '', [], null, undefined
|
||||
*/
|
||||
export const isEmptyValue = value => value == null || value.length === 0;
|
||||
|
||||
/**
|
||||
* A form object serializer
|
||||
*
|
||||
* @param {Object} - Form Object
|
||||
* @returns {Object} - Serialized Form Object
|
||||
*
|
||||
* @example
|
||||
* Input
|
||||
* {"project": {"value": "hello", "state": false}, "username": {"value": "john"}}
|
||||
*
|
||||
* Returns
|
||||
* {"project": "hello", "username": "john"}
|
||||
*/
|
||||
export const serializeFormObject = form =>
|
||||
Object.fromEntries(
|
||||
Object.entries(form).reduce((acc, [name, { value }]) => {
|
||||
if (!isEmptyValue(value)) {
|
||||
acc.push([name, value]);
|
||||
}
|
||||
return acc;
|
||||
}, []),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import { localTimeAgo } from './lib/utils/datetime_utility';
|
|||
import { getLocationHash, visitUrl } from './lib/utils/url_utility';
|
||||
|
||||
// everything else
|
||||
import loadAwardsHandler from './awards_handler';
|
||||
import { deprecatedCreateFlash as Flash, removeFlashClickListener } from './flash';
|
||||
import initTodoToggle from './header';
|
||||
import initImporterStatus from './importer_status';
|
||||
|
|
@ -37,7 +36,7 @@ import GlFieldErrors from './gl_field_errors';
|
|||
import initUserPopovers from './user_popovers';
|
||||
import initBroadcastNotifications from './broadcast_notification';
|
||||
import initPersistentUserCallouts from './persistent_user_callouts';
|
||||
import { initUserTracking } from './tracking';
|
||||
import { initUserTracking, initDefaultTrackers } from './tracking';
|
||||
import { __ } from './locale';
|
||||
|
||||
import 'ee_else_ce/main_ee';
|
||||
|
|
@ -111,6 +110,7 @@ function deferredInitialisation() {
|
|||
initBroadcastNotifications();
|
||||
initFrequentItemDropdowns();
|
||||
initPersistentUserCallouts();
|
||||
initDefaultTrackers();
|
||||
|
||||
if (document.querySelector('.search')) initSearchAutocomplete();
|
||||
|
||||
|
|
@ -154,8 +154,6 @@ function deferredInitialisation() {
|
|||
viewport: '.layout-page',
|
||||
});
|
||||
|
||||
loadAwardsHandler();
|
||||
|
||||
// Adding a helper class to activate animations only after all is rendered
|
||||
setTimeout(() => $body.addClass('page-initialised'), 1000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script>
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'ResolveDiscussionButton',
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
GlButton,
|
||||
},
|
||||
props: {
|
||||
isResolving: {
|
||||
|
|
@ -21,8 +21,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<button ref="button" type="button" class="btn btn-default ml-sm-2" @click="$emit('onClick')">
|
||||
<gl-loading-icon v-if="isResolving" ref="isResolvingIcon" inline />
|
||||
<gl-button :loading="isResolving" class="ml-sm-2" @click="$emit('onClick')">
|
||||
{{ buttonTitle }}
|
||||
</button>
|
||||
</gl-button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import syntaxHighlight from '~/syntax_highlight';
|
||||
import flash from '~/flash';
|
||||
import { __ } from '~/locale';
|
||||
import loadAwardsHandler from '~/awards_handler';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const hasPerfBar = document.querySelector('.with-performance-bar');
|
||||
|
|
@ -48,4 +49,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
} else {
|
||||
new Diff();
|
||||
}
|
||||
loadAwardsHandler();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import loadAwardsHandler from '~/awards_handler';
|
||||
import initIssuableSidebar from '~/init_issuable_sidebar';
|
||||
import Issue from '~/issue';
|
||||
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
|
||||
|
|
@ -37,4 +38,6 @@ export default function() {
|
|||
} else {
|
||||
initIssuableSidebar();
|
||||
}
|
||||
|
||||
loadAwardsHandler();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import howToMerge from '~/how_to_merge';
|
|||
import initPipelines from '~/commit/pipelines/pipelines_bundle';
|
||||
import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
|
||||
import initSourcegraph from '~/sourcegraph';
|
||||
import loadAwardsHandler from '~/awards_handler';
|
||||
|
||||
export default function() {
|
||||
new ZenMode(); // eslint-disable-line no-new
|
||||
|
|
@ -19,4 +20,5 @@ export default function() {
|
|||
handleLocationHash();
|
||||
howToMerge();
|
||||
initSourcegraph();
|
||||
loadAwardsHandler();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ export default {
|
|||
<ci-badge
|
||||
:status="pipelineStatus"
|
||||
:show-text="!isChildView"
|
||||
:icon-classes="'gl-vertical-align-middle!'"
|
||||
data-qa-selector="pipeline_commit_status"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ZenMode from '~/zen_mode';
|
|||
import initNotes from '~/init_notes';
|
||||
import snippetEmbed from '~/snippet/snippet_embed';
|
||||
import { SnippetShowInit } from '~/snippets';
|
||||
import loadAwardsHandler from '~/awards_handler';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!gon.features.snippetsVue) {
|
||||
|
|
@ -16,4 +17,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
SnippetShowInit();
|
||||
initNotes();
|
||||
}
|
||||
loadAwardsHandler();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -126,14 +126,18 @@ export function initUserTracking() {
|
|||
const opts = { ...DEFAULT_SNOWPLOW_OPTIONS, ...window.snowplowOptions };
|
||||
window.snowplow('newTracker', opts.namespace, opts.hostname, opts);
|
||||
|
||||
document.dispatchEvent(new Event('SnowplowInitialized'));
|
||||
}
|
||||
|
||||
export function initDefaultTrackers() {
|
||||
if (!Tracking.enabled()) return;
|
||||
|
||||
window.snowplow('enableActivityTracking', 30, 30);
|
||||
window.snowplow('trackPageView'); // must be after enableActivityTracking
|
||||
|
||||
if (opts.formTracking) window.snowplow('enableFormTracking');
|
||||
if (opts.linkClickTracking) window.snowplow('enableLinkClickTracking');
|
||||
if (window.snowplowOptions.formTracking) window.snowplow('enableFormTracking');
|
||||
if (window.snowplowOptions.linkClickTracking) window.snowplow('enableLinkClickTracking');
|
||||
|
||||
Tracking.bindDocument();
|
||||
Tracking.trackLoadEvents();
|
||||
|
||||
document.dispatchEvent(new Event('SnowplowInitialized'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ export default {
|
|||
required: false,
|
||||
default: true,
|
||||
},
|
||||
iconClasses: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
cssClass() {
|
||||
|
|
@ -55,7 +60,7 @@ export default {
|
|||
:class="cssClass"
|
||||
:title="!showText ? status.text : ''"
|
||||
>
|
||||
<ci-icon :status="status" />
|
||||
<ci-icon :status="status" :css-classes="iconClasses" />
|
||||
|
||||
<template v-if="showText">
|
||||
{{ status.text }}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
<script>
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { GlDrawer } from '@gitlab/ui';
|
||||
import { GlDrawer, GlBadge, GlIcon, GlLink } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDrawer,
|
||||
GlBadge,
|
||||
GlIcon,
|
||||
GlLink,
|
||||
},
|
||||
props: {
|
||||
features: {
|
||||
|
|
@ -37,16 +40,31 @@ export default {
|
|||
<div>
|
||||
<gl-drawer class="mt-6" :open="open" @close="closeDrawer">
|
||||
<template #header>
|
||||
<h4>{{ __("What's new at GitLab") }}</h4>
|
||||
</template>
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="feature in parsedFeatures" :key="feature.title">
|
||||
<h5>{{ feature.title }}</h5>
|
||||
<p>{{ feature.body }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h4 class="page-title my-2">{{ __("What's new at GitLab") }}</h4>
|
||||
</template>
|
||||
<div class="pb-6">
|
||||
<div v-for="feature in parsedFeatures" :key="feature.title" class="mb-6">
|
||||
<gl-link :href="feature.url" target="_blank">
|
||||
<h5 class="gl-font-base">{{ feature.title }}</h5>
|
||||
</gl-link>
|
||||
<div class="mb-2">
|
||||
<template v-for="package_name in feature.packages">
|
||||
<gl-badge :key="package_name" size="sm" class="whats-new-item-badge mr-1">
|
||||
<gl-icon name="license" />{{ package_name }}
|
||||
</gl-badge>
|
||||
</template>
|
||||
</div>
|
||||
<gl-link :href="feature.url" target="_blank">
|
||||
<img
|
||||
:alt="feature.title"
|
||||
:src="feature.image_url"
|
||||
class="img-thumbnail px-6 py-2 whats-new-item-image"
|
||||
/>
|
||||
</gl-link>
|
||||
<p class="pt-2">{{ feature.body }}</p>
|
||||
<gl-link :href="feature.url" target="_blank">{{ __('Learn more') }}</gl-link>
|
||||
</div>
|
||||
</div>
|
||||
</gl-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
.gl-badge.whats-new-item-badge {
|
||||
background-color: $purple-light;
|
||||
color: $purple;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.whats-new-item-image {
|
||||
border-color: $gray-50;
|
||||
}
|
||||
|
|
@ -116,7 +116,6 @@
|
|||
|
||||
.board-title {
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.board-title-caret {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,6 @@ class ProjectsController < Projects::ApplicationController
|
|||
|
||||
before_action only: [:edit] do
|
||||
push_frontend_feature_flag(:service_desk_custom_address, @project)
|
||||
end
|
||||
|
||||
before_action only: [:edit] do
|
||||
push_frontend_feature_flag(:approval_suggestions, @project)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -24,28 +24,20 @@ module Storage
|
|||
parent_full_path = parent&.full_path
|
||||
Gitlab::UploadsTransfer.new.move_namespace(path, former_parent_full_path, parent_full_path)
|
||||
|
||||
if ::Feature.enabled?(:async_pages_move_namespace_transfer, self)
|
||||
if any_project_with_pages_deployed?
|
||||
run_after_commit do
|
||||
Gitlab::PagesTransfer.new.async.move_namespace(path, former_parent_full_path, parent_full_path)
|
||||
end
|
||||
if any_project_with_pages_deployed?
|
||||
run_after_commit do
|
||||
Gitlab::PagesTransfer.new.async.move_namespace(path, former_parent_full_path, parent_full_path)
|
||||
end
|
||||
else
|
||||
Gitlab::PagesTransfer.new.move_namespace(path, former_parent_full_path, parent_full_path)
|
||||
end
|
||||
else
|
||||
Gitlab::UploadsTransfer.new.rename_namespace(full_path_before_last_save, full_path)
|
||||
|
||||
if ::Feature.enabled?(:async_pages_move_namespace_rename, self)
|
||||
if any_project_with_pages_deployed?
|
||||
full_path_was = full_path_before_last_save
|
||||
if any_project_with_pages_deployed?
|
||||
full_path_was = full_path_before_last_save
|
||||
|
||||
run_after_commit do
|
||||
Gitlab::PagesTransfer.new.async.rename_namespace(full_path_was, full_path)
|
||||
end
|
||||
run_after_commit do
|
||||
Gitlab::PagesTransfer.new.async.rename_namespace(full_path_was, full_path)
|
||||
end
|
||||
else
|
||||
Gitlab::PagesTransfer.new.rename_namespace(full_path_before_last_save, full_path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,7 @@ module Ci
|
|||
return result unless result[:status] == :success
|
||||
|
||||
headers = JobArtifactUploader.workhorse_authorize(has_length: false, maximum_size: max_size(artifact_type))
|
||||
|
||||
if lsif?(artifact_type)
|
||||
headers[:ProcessLsif] = true
|
||||
headers[:ProcessLsifReferences] = Feature.enabled?(:code_navigation_references, project, default_enabled: true)
|
||||
end
|
||||
headers[:ProcessLsif] = lsif?(artifact_type)
|
||||
|
||||
success(headers: headers)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
module Pages
|
||||
class DeleteService < BaseService
|
||||
def execute
|
||||
if Feature.enabled?(:async_pages_removal, project)
|
||||
PagesRemoveWorker.perform_async(project.id)
|
||||
else
|
||||
PagesRemoveWorker.new.perform(project.id)
|
||||
end
|
||||
PagesRemoveWorker.perform_async(project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -96,24 +96,18 @@ module Projects
|
|||
.rename_project(path_before, project_path, namespace_full_path)
|
||||
end
|
||||
|
||||
if ::Feature.enabled?(:async_pages_move_project_rename, project)
|
||||
if project.pages_deployed?
|
||||
# Block will be evaluated in the context of project so we need
|
||||
# to bind to a local variable to capture it, as the instance
|
||||
# variable and method aren't available on Project
|
||||
path_before_local = @path_before
|
||||
if project.pages_deployed?
|
||||
# Block will be evaluated in the context of project so we need
|
||||
# to bind to a local variable to capture it, as the instance
|
||||
# variable and method aren't available on Project
|
||||
path_before_local = @path_before
|
||||
|
||||
project.run_after_commit_or_now do
|
||||
Gitlab::PagesTransfer
|
||||
.new
|
||||
.async
|
||||
.rename_project(path_before_local, path, namespace.full_path)
|
||||
end
|
||||
project.run_after_commit_or_now do
|
||||
Gitlab::PagesTransfer
|
||||
.new
|
||||
.async
|
||||
.rename_project(path_before_local, path, namespace.full_path)
|
||||
end
|
||||
else
|
||||
Gitlab::PagesTransfer
|
||||
.new
|
||||
.rename_project(path_before, project_path, namespace_full_path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -181,15 +181,9 @@ module Projects
|
|||
end
|
||||
|
||||
def move_pages(project)
|
||||
transfer = Gitlab::PagesTransfer.new
|
||||
|
||||
if Feature.enabled?(:async_pages_move_project_transfer, project)
|
||||
# Avoid scheduling moves for directories that don't exist.
|
||||
return unless project.pages_deployed?
|
||||
|
||||
transfer = transfer.async
|
||||
end
|
||||
return unless project.pages_deployed?
|
||||
|
||||
transfer = Gitlab::PagesTransfer.new.async
|
||||
transfer.move_project(project.path, @old_namespace.full_path, @new_namespace.full_path)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,43 +13,42 @@
|
|||
|
||||
= render partial: 'flash_messages'
|
||||
|
||||
%div{ class: [("limit-container-width" unless fluid_layout)] }
|
||||
= render_if_exists 'trials/banner', namespace: @group
|
||||
= render_if_exists 'trials/banner', namespace: @group
|
||||
|
||||
= render 'groups/home_panel'
|
||||
= render 'groups/home_panel'
|
||||
|
||||
= render_if_exists 'groups/self_or_ancestor_marked_for_deletion_notice', group: @group
|
||||
= render_if_exists 'groups/self_or_ancestor_marked_for_deletion_notice', group: @group
|
||||
|
||||
= render_if_exists 'groups/group_activity_analytics', group: @group
|
||||
= render_if_exists 'groups/group_activity_analytics', group: @group
|
||||
|
||||
.groups-listing{ data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
|
||||
.top-area.group-nav-container.justify-content-between
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
%ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs
|
||||
%li.js-subgroups_and_projects-tab
|
||||
= link_to group_path, data: { target: 'div#subgroups_and_projects', action: 'subgroups_and_projects', toggle: 'tab'} do
|
||||
= _("Subgroups and projects")
|
||||
%li.js-shared-tab
|
||||
= link_to group_shared_path, data: { target: 'div#shared', action: 'shared', toggle: 'tab'} do
|
||||
= _("Shared projects")
|
||||
%li.js-archived-tab
|
||||
= link_to group_archived_path, data: { target: 'div#archived', action: 'archived', toggle: 'tab'} do
|
||||
= _("Archived projects")
|
||||
.groups-listing{ data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
|
||||
.top-area.group-nav-container.justify-content-between
|
||||
.scrolling-tabs-container.inner-page-scroll-tabs
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
%ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs
|
||||
%li.js-subgroups_and_projects-tab
|
||||
= link_to group_path, data: { target: 'div#subgroups_and_projects', action: 'subgroups_and_projects', toggle: 'tab'} do
|
||||
= _("Subgroups and projects")
|
||||
%li.js-shared-tab
|
||||
= link_to group_shared_path, data: { target: 'div#shared', action: 'shared', toggle: 'tab'} do
|
||||
= _("Shared projects")
|
||||
%li.js-archived-tab
|
||||
= link_to group_archived_path, data: { target: 'div#archived', action: 'archived', toggle: 'tab'} do
|
||||
= _("Archived projects")
|
||||
|
||||
.nav-controls.d-block.d-md-flex
|
||||
.group-search
|
||||
= render "shared/groups/search_form"
|
||||
.nav-controls.d-block.d-md-flex
|
||||
.group-search
|
||||
= render "shared/groups/search_form"
|
||||
|
||||
= render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
|
||||
= render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
|
||||
|
||||
.tab-content
|
||||
#subgroups_and_projects.tab-pane
|
||||
= render "subgroups_and_projects", group: @group
|
||||
.tab-content
|
||||
#subgroups_and_projects.tab-pane
|
||||
= render "subgroups_and_projects", group: @group
|
||||
|
||||
#shared.tab-pane
|
||||
= render "shared_projects", group: @group
|
||||
#shared.tab-pane
|
||||
= render "shared_projects", group: @group
|
||||
|
||||
#archived.tab-pane
|
||||
= render "archived_projects", group: @group
|
||||
#archived.tab-pane
|
||||
= render "archived_projects", group: @group
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
.flash-text
|
||||
.loading-metrics.js-loading-custom-metrics
|
||||
%p.m-3
|
||||
= icon('spinner spin', class: 'metrics-load-spinner')
|
||||
= loading_icon(css_class: 'metrics-load-spinner')
|
||||
= s_('PrometheusService|Finding custom metrics...')
|
||||
.empty-metrics.hidden.js-empty-custom-metrics
|
||||
%p.text-tertiary.m-3.js-no-active-integration-text.hidden
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
.card-body
|
||||
.loading-metrics.js-loading-metrics
|
||||
%p.m-3
|
||||
= icon('spinner spin', class: 'metrics-load-spinner')
|
||||
= loading_icon(css_class: 'metrics-load-spinner')
|
||||
= s_('PrometheusService|Finding and configuring metrics...')
|
||||
.empty-metrics.hidden.js-empty-metrics
|
||||
%p.text-tertiary.m-3
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
#js-suggestions{ data: { project_path: @project.full_path } }
|
||||
|
||||
= render 'shared/form_elements/apply_template_warning'
|
||||
|
||||
- if issuable.is_a?(Issuable) && @issue
|
||||
= render 'shared/issuable/form/type_selector', issuable: issuable, form: form, type: @issue[:issue_type]
|
||||
|
||||
= render 'shared/form_elements/description', model: issuable, form: form, project: project
|
||||
|
||||
- if issuable.respond_to?(:confidential)
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@
|
|||
|
||||
= render_if_exists "shared/issuable/form/epic", issuable: issuable, form: form, project: project
|
||||
|
||||
.form-group.row.issue-milestone
|
||||
= form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
|
||||
.col-sm-10{ class: ("col-md-8" if has_due_date) }
|
||||
.issuable-form-select-holder
|
||||
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
|
||||
- if issuable.supports_milestone?
|
||||
.form-group.row.issue-milestone
|
||||
= form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
|
||||
.col-sm-10{ class: ("col-md-8" if has_due_date) }
|
||||
.issuable-form-select-holder
|
||||
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
|
||||
|
||||
.form-group.row
|
||||
= form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
|
||||
= form.hidden_field :label_ids, multiple: true, value: ''
|
||||
|
|
@ -30,7 +32,8 @@
|
|||
|
||||
- if has_due_date || issuable.supports_weight?
|
||||
.col-lg-6
|
||||
= render_if_exists "shared/issuable/form/weight", issuable: issuable, form: form
|
||||
- if @issue[:issue_type] != 'incident'
|
||||
= render_if_exists "shared/issuable/form/weight", issuable: issuable, form: form
|
||||
.form-group.row
|
||||
= form.label :due_date, "Due date", class: "col-form-label col-md-2 col-lg-4"
|
||||
.col-8
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
.form-group.row.gl-mb-0
|
||||
= form.label :type, 'Type', class: 'col-form-label col-sm-2'
|
||||
.col-sm-10
|
||||
.issuable-form-select-holder.selectbox.form-group
|
||||
.dropdown.js-issuable-type-filter-dropdown-wrap
|
||||
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%span.dropdown-label
|
||||
= type.capitalize || _("Select type")
|
||||
= icon('chevron-down')
|
||||
.dropdown-menu.dropdown-menu-selectable.dropdown-select
|
||||
.dropdown-title
|
||||
= _("Select type")
|
||||
%button.dropdown-title-button.dropdown-menu-close.gl-mt-3
|
||||
= icon('times', class: 'dropdown-menu-close-icon', 'aria-hidden' => 'true')
|
||||
.dropdown-content
|
||||
%ul
|
||||
%li.js-filter-issuable-type
|
||||
= link_to new_project_issue_path(@project), class: ("is-active" if type === 'issue') do
|
||||
= _("Issue")
|
||||
%li.js-filter-issuable-type
|
||||
= link_to new_project_issue_path(@project, { 'issue[issue_type]': 'incident', issuable_template: 'incident' }), class: ("is-active" if type === 'incident') do
|
||||
= _("Incident")
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate '.fa-spinner' to '.spinner' for 'app/views/projects/services/prometheus'
|
||||
merge_request: 41126
|
||||
author: Gilang Gumilar
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Defer (certain) parts of setting up snowplow telemetry
|
||||
merge_request: 40299
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add type selector dropdown to new issue form
|
||||
merge_request: 40981
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove the async pages feature flags
|
||||
merge_request: 40980
|
||||
author:
|
||||
type: performance
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Drop one of duplicated limit-container-width classname
|
||||
merge_request: 41251
|
||||
author: Takuya Noguchi
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update pipeline button SVG to be center aligned
|
||||
merge_request: 41066
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix Rails/SaveBang offenses for ee/spec/lib/gitlab/geo/*
|
||||
merge_request: 41338
|
||||
author: Rajendra Kadam
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update dependency vuex to ^3.5.1
|
||||
merge_request: 39201
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: async_pages_move_namespace_rename
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40259
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235808
|
||||
group: team::Scalability
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: async_pages_move_namespace_transfer
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40259
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235808
|
||||
group: team::Scalability
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: async_pages_move_project_rename
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40087
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235802
|
||||
group: team::Scalability
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: async_pages_move_project_transfer
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40492
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235757
|
||||
group: team::Scalability
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
name: async_pages_removal
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38313
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239318
|
||||
group: team::Scalability
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -59,7 +59,7 @@ if gitlab.mr_labels.include?('database') || db_paths_to_review.any?
|
|||
markdown(DB_MESSAGE)
|
||||
markdown(DB_FILES_MESSAGE + helper.markdown_list(db_paths_to_review)) if db_paths_to_review.any?
|
||||
|
||||
unless has_database_scoped_labels?(gitlab.mr_labels)
|
||||
unless helper.has_database_scoped_labels?(gitlab.mr_labels)
|
||||
gitlab.api.update_merge_request(gitlab.mr_json['project_id'],
|
||||
gitlab.mr_json['iid'],
|
||||
add_labels: 'database::review pending')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
stage: Plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: ultimate, gold
|
||||
packages: [Ultimate, Gold]
|
||||
url: https://docs.gitlab.com/ee/user/project/requirements/index.html
|
||||
image_url:
|
||||
published_at: 2020-04-22
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
stage: Release
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/ci/examples/authenticating-with-hashicorp-vault/index.html
|
||||
image_url: https://about.gitlab.com/images/12_10/jwt-vault-1.png
|
||||
published_at: 2020-04-22
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
stage: Plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: ultimate, gold
|
||||
packages: [Ultimate, Gold]
|
||||
url: https://docs.gitlab.com/ee/user/project/issues/index.html#health-status-ultimate
|
||||
image_url: https://about.gitlab.com/images/12_10/epic-health-status.png
|
||||
published_at: 2020-04-22
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
stage: Plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/import/jira.html
|
||||
image_url: https://about.gitlab.com/images/12_10/jira-importer.png
|
||||
published_at: 2020-04-22
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
stage: Verify
|
||||
self-managed: true
|
||||
gitlab-com: false
|
||||
packages: core, starter, premium, ultimate
|
||||
packages: [Core, Starter, Premium, Ultimate]
|
||||
url: https://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/fargate/-/blob/master/docs/README.md
|
||||
image_url: https://about.gitlab.com/images/12_9/autoscaling_ci_fargate.png
|
||||
published_at: 2020-04-22
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: false
|
||||
packages: core, starter, premium, ultimate
|
||||
packages: [Core, Starter, Premium, Ultimate]
|
||||
url: https://docs.gitlab.com/ee/administration/gitaly/praefect.html
|
||||
image_url: https://about.gitlab.com/images/13_0/praefect-architecture.png
|
||||
published_at: 2020-05-22
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
stage: Release
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/topics/autodevops/index.html#aws-ecs
|
||||
image_url:
|
||||
published_at: 2020-05-22
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
stage: Plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: ultimate, gold
|
||||
packages: [Ultimate, Gold]
|
||||
url: https://docs.gitlab.com/ee/user/group/roadmap/
|
||||
image_url: https://about.gitlab.com/images/13_0/Expand-Epic-Hierarchy-Roadmap_roadmap.png
|
||||
published_at: 2020-05-22
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/snippets.html#versioned-snippets
|
||||
image_url: https://about.gitlab.com/images/13_0/phikai-versioned-snippets.png
|
||||
published_at: 2020-05-22
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/web_ide/#themes
|
||||
image_url: https://about.gitlab.com/images/13_0/phikai-web-ide-dark-theme.png
|
||||
published_at: 2020-05-22
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
stage: Monitor
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/operations/alert_management.html
|
||||
image_url: https://about.gitlab.com/images/13_1/alert_management.png
|
||||
published_at: 2020-06-22
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
stage: Verify
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/merge_requests/accessibility_testing.html#accessibility-merge-request-widget
|
||||
image_url: https://about.gitlab.com/images/13_1/a11y-merge-request-widget.png
|
||||
published_at: 2020-06-22
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/issues/design_management.html#resolve-design-threads
|
||||
image_url: https://about.gitlab.com/images/13_1/resolve-design-comment.gif
|
||||
published_at: 2020-06-22
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
stage: Create
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/discussions/index.html#merge-request-reviews
|
||||
image_url: https://about.gitlab.com/images/13_1/batch_comments.png
|
||||
published_at: 2020-06-22
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
stage: Plan
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: starter, premium, ultimate
|
||||
packages: [Starter, Premium, Ultimate]
|
||||
url: https://www.youtube.com/watch?v=31pNKjenlJY&feature=emb_title
|
||||
image_url: http://i3.ytimg.com/vi/31pNKjenlJY/maxresdefault.jpg
|
||||
published_at: 2020-07-22
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
stage: Defend
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://www.youtube.com/watch?v=WxBzBz76FxU&feature=youtu.be
|
||||
image_url: http://i3.ytimg.com/vi/WxBzBz76FxU/hqdefault.jpg
|
||||
published_at: 2020-07-22
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
stage: Create
|
||||
self-managed: false
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/issues/design_management.html#gitlab-figma-plugin
|
||||
image_url: https://about.gitlab.com/images/13_2/figma-plugin.png
|
||||
published_at: 2020-07-22
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
stage: Monitor
|
||||
self-managed: true
|
||||
gitlab-com: true
|
||||
packages: All
|
||||
packages: [All]
|
||||
url: https://docs.gitlab.com/ee/user/project/clusters/#visualizing-cluster-health
|
||||
image_url: https://about.gitlab.com/images/13_2/k8s_cluster_monitoring.png
|
||||
published_at: 2020-07-22
|
||||
|
|
|
|||
|
|
@ -11352,6 +11352,16 @@ type Project {
|
|||
last: Int
|
||||
): DastScannerProfileConnection
|
||||
|
||||
"""
|
||||
DAST Site Profile associated with the project
|
||||
"""
|
||||
dastSiteProfile(
|
||||
"""
|
||||
ID of the site profile
|
||||
"""
|
||||
id: DastSiteProfileID!
|
||||
): DastSiteProfile
|
||||
|
||||
"""
|
||||
DAST Site Profiles associated with the project
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -33932,6 +33932,33 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastSiteProfile",
|
||||
"description": "DAST Site Profile associated with the project",
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "ID of the site profile",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DastSiteProfileID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastSiteProfile",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastSiteProfiles",
|
||||
"description": "DAST Site Profiles associated with the project",
|
||||
|
|
|
|||
|
|
@ -1737,6 +1737,7 @@ Autogenerated return type of PipelineRetry
|
|||
| `containerExpirationPolicy` | ContainerExpirationPolicy | The container expiration policy of the project |
|
||||
| `containerRegistryEnabled` | Boolean | Indicates if the project stores Docker container images in a container registry |
|
||||
| `createdAt` | Time | Timestamp of the project creation |
|
||||
| `dastSiteProfile` | DastSiteProfile | DAST Site Profile associated with the project |
|
||||
| `description` | String | Short description of the project |
|
||||
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
|
||||
| `environment` | Environment | A single environment of the project |
|
||||
|
|
|
|||
|
|
@ -776,7 +776,7 @@ POST /user/keys
|
|||
|
||||
Parameters:
|
||||
|
||||
- `title` (required) - new SSH Key's title
|
||||
- `title` (required) - new SSH key's title
|
||||
- `key` (required) - new SSH key
|
||||
- `expires_at` (optional) - The expiration date of the SSH key in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)
|
||||
|
||||
|
|
@ -815,7 +815,7 @@ POST /users/:id/keys
|
|||
Parameters:
|
||||
|
||||
- `id` (required) - ID of specified user
|
||||
- `title` (required) - new SSH Key's title
|
||||
- `title` (required) - new SSH key's title
|
||||
- `key` (required) - new SSH key
|
||||
- `expires_at` (optional) - The expiration date of the SSH key in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
# GitLab development style guides
|
||||
|
||||
See below the relevant style guides, guidelines, linting, and other information for developing GitLab.
|
||||
See below for the relevant style guides, guidelines, linting, and other information for developing GitLab.
|
||||
|
||||
## JavaScript style guide
|
||||
|
||||
We use `eslint` to enforce our [JavaScript style guides](javascript.md). Our guide is based on
|
||||
the excellent [AirBnB](https://github.com/airbnb/javascript) style guide with a few small
|
||||
the excellent [Airbnb](https://github.com/airbnb/javascript) style guide with a few small
|
||||
changes.
|
||||
|
||||
## SCSS style guide
|
||||
|
|
|
|||
|
|
@ -711,7 +711,8 @@ If your namespace shows `N/A` as the total storage usage, you can trigger a reca
|
|||
|
||||
#### Group push rules **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34370) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.8.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34370) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.8.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/224129) in GitLab 13.4.
|
||||
|
||||
Group push rules allow group maintainers to set
|
||||
[push rules](../../push_rules/push_rules.md) for newly created projects within the specific group.
|
||||
|
|
@ -724,14 +725,6 @@ When set, new subgroups have push rules set for them based on either:
|
|||
- The closest parent group with push rules defined.
|
||||
- Push rules set at the instance level, if no parent groups have push rules defined.
|
||||
|
||||
##### Enabling the feature
|
||||
|
||||
This feature comes with the `:group_push_rules` feature flag disabled by default. It can be enabled for specific group using feature flag [API endpoint](../../api/features.md#set-or-create-a-feature) or by GitLab administrator with Rails console access by running:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:group_push_rules)
|
||||
```
|
||||
|
||||
### Maximum artifacts size **(CORE ONLY)**
|
||||
|
||||
For information about setting a maximum artifact size for a group, see
|
||||
|
|
|
|||
|
|
@ -39,38 +39,18 @@ The generated LSIF file must be less than 170MiB.
|
|||
|
||||
After the job succeeds, code intelligence data can be viewed while browsing the code:
|
||||
|
||||

|
||||

|
||||
|
||||
## Find references
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217392) in GitLab 13.2.
|
||||
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/225621) on GitLab 13.3.
|
||||
> - It's enabled on GitLab.com.
|
||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/235735) in GitLab 13.4.
|
||||
|
||||
To find where a particular object is being used, you can see links to specific lines of code
|
||||
under the **References** tab:
|
||||
|
||||

|
||||
|
||||
### Enable or disable find references
|
||||
|
||||
Find references is under development but ready for production use.
|
||||
It is deployed behind a feature flag that is **enabled by default**.
|
||||
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
|
||||
can opt to disable it for your instance.
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:code_navigation_references)
|
||||
```
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:code_navigation_references)
|
||||
```
|
||||
|
||||
## Language support
|
||||
|
||||
Generating an LSIF file requires a language server indexer implementation for the
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
|
|
@ -12,7 +12,7 @@ module Gitlab
|
|||
:seeds_block, :variables_attributes, :push_options,
|
||||
:chat_data, :allow_mirror_update, :bridge, :content, :dry_run,
|
||||
# These attributes are set by Chains during processing:
|
||||
:config_content, :config_processor, :stage_seeds
|
||||
:config_content, :yaml_processor_result, :stage_seeds
|
||||
) do
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Gitlab
|
|||
add_warnings_to_pipeline(result.warnings)
|
||||
|
||||
if result.valid?
|
||||
@command.config_processor = result
|
||||
@command.yaml_processor_result = result
|
||||
else
|
||||
error(result.errors.first, config_error: true)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def workflow_config
|
||||
@command.config_processor.workflow_attributes || {}
|
||||
@command.yaml_processor_result.workflow_attributes || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ module Gitlab
|
|||
module Chain
|
||||
class RemoveUnwantedChatJobs < Chain::Base
|
||||
def perform!
|
||||
raise ArgumentError, 'missing config processor' unless @command.config_processor
|
||||
raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
|
||||
|
||||
return unless pipeline.chat?
|
||||
|
||||
# When scheduling a chat pipeline we only want to run the build
|
||||
# that matches the chat command.
|
||||
@command.config_processor.jobs.select! do |name, _|
|
||||
@command.yaml_processor_result.jobs.select! do |name, _|
|
||||
name.to_s == command.chat_data[:command].to_s
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module Gitlab
|
|||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def perform!
|
||||
raise ArgumentError, 'missing config processor' unless @command.config_processor
|
||||
raise ArgumentError, 'missing YAML processor result' unless @command.yaml_processor_result
|
||||
|
||||
# Allocate next IID. This operation must be outside of transactions of pipeline creations.
|
||||
pipeline.ensure_project_iid!
|
||||
|
|
@ -56,7 +56,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def stages_attributes
|
||||
@command.config_processor.stages_attributes
|
||||
@command.yaml_processor_result.stages_attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ module Gitlab
|
|||
def validate_service_request
|
||||
Gitlab::HTTP.post(
|
||||
validation_service_url, timeout: VALIDATION_REQUEST_TIMEOUT,
|
||||
body: validation_service_payload(@pipeline, @command.config_processor.stages_attributes)
|
||||
body: validation_service_payload(@pipeline, @command.yaml_processor_result.stages_attributes)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ module Gitlab
|
|||
# Files that don't fit into any category are marked with :none
|
||||
%r{\A(ee/)?changelogs/} => :none,
|
||||
%r{\Alocale/gitlab\.pot\z} => :none,
|
||||
%r{\Adata/whats_new/} => :none,
|
||||
|
||||
# Fallbacks in case the above patterns miss anything
|
||||
%r{\.rb\z} => :backend,
|
||||
|
|
|
|||
|
|
@ -1162,7 +1162,7 @@ msgstr ""
|
|||
msgid "A merge request approval is required when a security report contains a new vulnerability of high, critical, or unknown severity."
|
||||
msgstr ""
|
||||
|
||||
msgid "A merge request approval is required when the license compliance report contains a blacklisted license."
|
||||
msgid "A merge request approval is required when the license compliance report contains a denied license."
|
||||
msgstr ""
|
||||
|
||||
msgid "A new Auto DevOps pipeline has been created, go to %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details"
|
||||
|
|
@ -2873,6 +2873,9 @@ msgstr ""
|
|||
msgid "An error occurred while updating the comment"
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while updating the list. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "An error occurred while validating group path"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7704,6 +7707,9 @@ msgstr ""
|
|||
msgid "DAG visualization requires at least 3 dependent jobs."
|
||||
msgstr ""
|
||||
|
||||
msgid "DAST Profiles"
|
||||
msgstr ""
|
||||
|
||||
msgid "DNS"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7737,6 +7743,9 @@ msgstr ""
|
|||
msgid "DastProfiles|Are you sure you want to delete this profile?"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Could not create the scanner profile. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Could not create the site profile. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7761,6 +7770,9 @@ msgstr ""
|
|||
msgid "DastProfiles|Could not update the site profile. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Do you want to discard this scanner profile?"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Do you want to discard this site profile?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7782,10 +7794,13 @@ msgstr ""
|
|||
msgid "DastProfiles|Manage profiles"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|New Profile"
|
||||
msgid "DastProfiles|Minimum = 0 (no timeout enabled), Maximum = 2880 minutes"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|New Scanner Profile"
|
||||
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|New Profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|New scanner profile"
|
||||
|
|
@ -7800,6 +7815,9 @@ msgstr ""
|
|||
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Please enter a valid timeout value"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Profile name"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -7821,9 +7839,21 @@ msgstr ""
|
|||
msgid "DastProfiles|Site Profiles"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Spider timeout"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Target URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|Target timeout"
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
|
||||
msgstr ""
|
||||
|
||||
msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
|
||||
msgstr ""
|
||||
|
||||
msgid "Data is still calculating..."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -13076,6 +13106,9 @@ msgstr ""
|
|||
msgid "In the next step, you'll be able to select the projects you want to import."
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incident Management Limits"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21481,6 +21514,9 @@ msgstr ""
|
|||
msgid "Save variables"
|
||||
msgstr ""
|
||||
|
||||
msgid "Saved scan settings and target site settings which are reusable."
|
||||
msgstr ""
|
||||
|
||||
msgid "Saving"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21774,6 +21810,9 @@ msgstr ""
|
|||
msgid "Secondary"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr ""
|
||||
|
||||
msgid "Secret"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21816,6 +21855,9 @@ msgstr ""
|
|||
msgid "SecurityConfiguration|An error occurred while creating the merge request."
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Available for on-demand DAST"
|
||||
msgstr ""
|
||||
|
||||
msgid "SecurityConfiguration|Configure"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -22248,6 +22290,9 @@ msgstr ""
|
|||
msgid "Select timezone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select type"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select user"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@
|
|||
"vue-template-compiler": "^2.6.10",
|
||||
"vue-virtual-scroll-list": "^1.4.4",
|
||||
"vuedraggable": "^2.23.0",
|
||||
"vuex": "^3.1.0",
|
||||
"vuex": "^3.5.1",
|
||||
"webpack": "^4.42.0",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ RSpec.describe 'Group navbar' do
|
|||
nav_item: _('Merge Requests'),
|
||||
nav_sub_items: []
|
||||
},
|
||||
(push_rules_nav_item if Gitlab.ee?),
|
||||
{
|
||||
nav_item: _('Kubernetes'),
|
||||
nav_sub_items: []
|
||||
|
|
@ -47,7 +48,6 @@ RSpec.describe 'Group navbar' do
|
|||
before do
|
||||
insert_package_nav(_('Kubernetes'))
|
||||
|
||||
stub_feature_flags(group_push_rules: false)
|
||||
stub_feature_flags(group_iterations: false)
|
||||
stub_feature_flags(group_wiki: false)
|
||||
group.add_maintainer(user)
|
||||
|
|
|
|||
|
|
@ -188,6 +188,46 @@ RSpec.describe "User creates issue" do
|
|||
end
|
||||
end
|
||||
|
||||
context 'form create handles issue creation by default' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
visit new_project_issue_path(project)
|
||||
end
|
||||
|
||||
it 'pre-fills the issue type dropdown with issue type' do
|
||||
expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-label')).to have_content('Issue')
|
||||
end
|
||||
|
||||
it 'does not hide the milestone select' do
|
||||
expect(page).to have_selector('.qa-issuable-milestone-dropdown')
|
||||
end
|
||||
end
|
||||
|
||||
context 'form create handles incident creation' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
visit new_project_issue_path(project, { 'issue[issue_type]': 'incident', issuable_template: 'incident' })
|
||||
end
|
||||
|
||||
it 'pre-fills the issue type dropdown with incident type' do
|
||||
expect(find('.js-issuable-type-filter-dropdown-wrap .dropdown-label')).to have_content('Incident')
|
||||
end
|
||||
|
||||
it 'hides the epic select' do
|
||||
expect(page).not_to have_selector('.epic-dropdown-container')
|
||||
end
|
||||
|
||||
it 'hides the milestone select' do
|
||||
expect(page).not_to have_selector('.qa-issuable-milestone-dropdown')
|
||||
end
|
||||
|
||||
it 'hides the weight input' do
|
||||
expect(page).not_to have_selector('.qa-issuable-weight-input')
|
||||
end
|
||||
end
|
||||
|
||||
context 'suggestions', :js do
|
||||
it 'displays list of related issues' do
|
||||
issue = create(:issue, project: project)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ describe('AddContextCommitsModal', () => {
|
|||
findSearch().vm.$emit('input', searchText);
|
||||
expect(searchCommits).not.toBeCalled();
|
||||
jest.advanceTimersByTime(500);
|
||||
expect(searchCommits).toHaveBeenCalledWith(expect.anything(), searchText, undefined);
|
||||
expect(searchCommits).toHaveBeenCalledWith(expect.anything(), searchText);
|
||||
});
|
||||
|
||||
it('disabled ok button when no row is selected', () => {
|
||||
|
|
@ -119,18 +119,17 @@ describe('AddContextCommitsModal', () => {
|
|||
wrapper.vm.$store.state.selectedCommits = [{ ...commit, isSelected: true }];
|
||||
findModal().vm.$emit('ok');
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(createContextCommits).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ commits: [{ ...commit, isSelected: true }], forceReload: true },
|
||||
undefined,
|
||||
);
|
||||
expect(createContextCommits).toHaveBeenCalledWith(expect.anything(), {
|
||||
commits: [{ ...commit, isSelected: true }],
|
||||
forceReload: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
it('"removeContextCommits" when only added commits are to be removed ', () => {
|
||||
wrapper.vm.$store.state.toRemoveCommits = [commit.short_id];
|
||||
findModal().vm.$emit('ok');
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), true, undefined);
|
||||
expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), true);
|
||||
});
|
||||
});
|
||||
it('"createContextCommits" and "removeContextCommits" when new commits are to be added and old commits are to be removed', () => {
|
||||
|
|
@ -138,12 +137,10 @@ describe('AddContextCommitsModal', () => {
|
|||
wrapper.vm.$store.state.toRemoveCommits = [commit.short_id];
|
||||
findModal().vm.$emit('ok');
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(createContextCommits).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ commits: [{ ...commit, isSelected: true }] },
|
||||
undefined,
|
||||
);
|
||||
expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
|
||||
expect(createContextCommits).toHaveBeenCalledWith(expect.anything(), {
|
||||
commits: [{ ...commit, isSelected: true }],
|
||||
});
|
||||
expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -156,7 +153,7 @@ describe('AddContextCommitsModal', () => {
|
|||
});
|
||||
it('"resetModalState" to reset all the modal state', () => {
|
||||
findModal().vm.$emit('cancel');
|
||||
expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
|
||||
expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -168,7 +165,7 @@ describe('AddContextCommitsModal', () => {
|
|||
});
|
||||
it('"resetModalState" to reset all the modal state', () => {
|
||||
findModal().vm.$emit('close');
|
||||
expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
|
||||
expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import testAction from 'helpers/vuex_action_helper';
|
||||
import { mockListsWithModel } from '../mock_data';
|
||||
import actions, { gqlClient } from '~/boards/stores/actions';
|
||||
import * as types from '~/boards/stores/mutation_types';
|
||||
import { inactiveId, ListType } from '~/boards/constants';
|
||||
|
|
@ -160,8 +161,63 @@ describe('createList', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('moveList', () => {
|
||||
it('should commit MOVE_LIST mutation and dispatch updateList action', done => {
|
||||
const state = {
|
||||
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
|
||||
boardType: 'group',
|
||||
disabled: false,
|
||||
boardLists: mockListsWithModel,
|
||||
};
|
||||
|
||||
testAction(
|
||||
actions.moveList,
|
||||
{ listId: 'gid://gitlab/List/1', newIndex: 1, adjustmentValue: 1 },
|
||||
state,
|
||||
[
|
||||
{
|
||||
type: types.MOVE_LIST,
|
||||
payload: { movedList: mockListsWithModel[0], listAtNewIndex: mockListsWithModel[1] },
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
type: 'updateList',
|
||||
payload: { listId: 'gid://gitlab/List/1', position: 0, backupList: mockListsWithModel },
|
||||
},
|
||||
],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateList', () => {
|
||||
expectNotImplemented(actions.updateList);
|
||||
it('should commit UPDATE_LIST_FAILURE mutation when API returns an error', done => {
|
||||
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
|
||||
data: {
|
||||
updateBoardList: {
|
||||
list: {},
|
||||
errors: [{ foo: 'bar' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const state = {
|
||||
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
|
||||
boardType: 'group',
|
||||
disabled: false,
|
||||
boardLists: [{ type: 'closed' }],
|
||||
};
|
||||
|
||||
testAction(
|
||||
actions.updateList,
|
||||
{ listId: 'gid://gitlab/List/1', position: 1 },
|
||||
state,
|
||||
[{ type: types.UPDATE_LIST_FAILURE }],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteList', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import mutations from '~/boards/stores/mutations';
|
||||
import * as types from '~/boards/stores/mutation_types';
|
||||
import defaultState from '~/boards/stores/state';
|
||||
import { listObj, listObjDuplicate, mockIssue } from '../mock_data';
|
||||
import { listObj, listObjDuplicate, mockIssue, mockListsWithModel } from '../mock_data';
|
||||
|
||||
const expectNotImplemented = action => {
|
||||
it('is not implemented', () => {
|
||||
|
|
@ -92,16 +92,35 @@ describe('Board Store Mutations', () => {
|
|||
expectNotImplemented(mutations.RECEIVE_ADD_LIST_ERROR);
|
||||
});
|
||||
|
||||
describe('REQUEST_UPDATE_LIST', () => {
|
||||
expectNotImplemented(mutations.REQUEST_UPDATE_LIST);
|
||||
describe('MOVE_LIST', () => {
|
||||
it('updates boardLists state with reordered lists', () => {
|
||||
state = {
|
||||
...state,
|
||||
boardLists: mockListsWithModel,
|
||||
};
|
||||
|
||||
mutations.MOVE_LIST(state, {
|
||||
movedList: mockListsWithModel[0],
|
||||
listAtNewIndex: mockListsWithModel[1],
|
||||
});
|
||||
|
||||
expect(state.boardLists).toEqual([mockListsWithModel[1], mockListsWithModel[0]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_UPDATE_LIST_SUCCESS', () => {
|
||||
expectNotImplemented(mutations.RECEIVE_UPDATE_LIST_SUCCESS);
|
||||
});
|
||||
describe('UPDATE_LIST_FAILURE', () => {
|
||||
it('updates boardLists state with previous order and sets error message', () => {
|
||||
state = {
|
||||
...state,
|
||||
boardLists: [mockListsWithModel[1], mockListsWithModel[0]],
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
describe('RECEIVE_UPDATE_LIST_ERROR', () => {
|
||||
expectNotImplemented(mutations.RECEIVE_UPDATE_LIST_ERROR);
|
||||
mutations.UPDATE_LIST_FAILURE(state, mockListsWithModel);
|
||||
|
||||
expect(state.boardLists).toEqual(mockListsWithModel);
|
||||
expect(state.error).toEqual('An error occurred while updating the list. Please try again.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('REQUEST_REMOVE_LIST', () => {
|
||||
|
|
|
|||
|
|
@ -401,43 +401,33 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setRegion action', () => {
|
||||
expect(actions.setRegion).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
|
||||
expect(actions.setRegion).toHaveBeenCalledWith(expect.anything(), { region });
|
||||
});
|
||||
|
||||
it('fetches available vpcs', () => {
|
||||
expect(vpcsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
|
||||
expect(vpcsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region });
|
||||
});
|
||||
|
||||
it('fetches available key pairs', () => {
|
||||
expect(keyPairsActions.fetchItems).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ region },
|
||||
undefined,
|
||||
);
|
||||
expect(keyPairsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region });
|
||||
});
|
||||
|
||||
it('cleans selected vpc', () => {
|
||||
expect(actions.setVpc).toHaveBeenCalledWith(expect.anything(), { vpc: null }, undefined);
|
||||
expect(actions.setVpc).toHaveBeenCalledWith(expect.anything(), { vpc: null });
|
||||
});
|
||||
|
||||
it('cleans selected key pair', () => {
|
||||
expect(actions.setKeyPair).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ keyPair: null },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setKeyPair).toHaveBeenCalledWith(expect.anything(), { keyPair: null });
|
||||
});
|
||||
|
||||
it('cleans selected subnet', () => {
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] }, undefined);
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] });
|
||||
});
|
||||
|
||||
it('cleans selected security group', () => {
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ securityGroup: null },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(expect.anything(), {
|
||||
securityGroup: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -446,11 +436,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
|
||||
findClusterNameInput().vm.$emit('input', clusterName);
|
||||
|
||||
expect(actions.setClusterName).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ clusterName },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setClusterName).toHaveBeenCalledWith(expect.anything(), { clusterName });
|
||||
});
|
||||
|
||||
it('dispatches setEnvironmentScope when environment scope input changes', () => {
|
||||
|
|
@ -458,11 +444,9 @@ describe('EksClusterConfigurationForm', () => {
|
|||
|
||||
findEnvironmentScopeInput().vm.$emit('input', environmentScope);
|
||||
|
||||
expect(actions.setEnvironmentScope).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ environmentScope },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setEnvironmentScope).toHaveBeenCalledWith(expect.anything(), {
|
||||
environmentScope,
|
||||
});
|
||||
});
|
||||
|
||||
it('dispatches setKubernetesVersion when kubernetes version dropdown changes', () => {
|
||||
|
|
@ -470,11 +454,9 @@ describe('EksClusterConfigurationForm', () => {
|
|||
|
||||
findKubernetesVersionDropdown().vm.$emit('input', kubernetesVersion);
|
||||
|
||||
expect(actions.setKubernetesVersion).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ kubernetesVersion },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setKubernetesVersion).toHaveBeenCalledWith(expect.anything(), {
|
||||
kubernetesVersion,
|
||||
});
|
||||
});
|
||||
|
||||
it('dispatches setGitlabManagedCluster when gitlab managed cluster input changes', () => {
|
||||
|
|
@ -482,11 +464,9 @@ describe('EksClusterConfigurationForm', () => {
|
|||
|
||||
findGitlabManagedClusterCheckbox().vm.$emit('input', gitlabManagedCluster);
|
||||
|
||||
expect(actions.setGitlabManagedCluster).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ gitlabManagedCluster },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setGitlabManagedCluster).toHaveBeenCalledWith(expect.anything(), {
|
||||
gitlabManagedCluster,
|
||||
});
|
||||
});
|
||||
|
||||
describe('when vpc is selected', () => {
|
||||
|
|
@ -499,35 +479,28 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setVpc action', () => {
|
||||
expect(actions.setVpc).toHaveBeenCalledWith(expect.anything(), { vpc }, undefined);
|
||||
expect(actions.setVpc).toHaveBeenCalledWith(expect.anything(), { vpc });
|
||||
});
|
||||
|
||||
it('cleans selected subnet', () => {
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] }, undefined);
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet: [] });
|
||||
});
|
||||
|
||||
it('cleans selected security group', () => {
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ securityGroup: null },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(expect.anything(), {
|
||||
securityGroup: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('dispatches fetchSubnets action', () => {
|
||||
expect(subnetsActions.fetchItems).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ vpc, region },
|
||||
undefined,
|
||||
);
|
||||
expect(subnetsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { vpc, region });
|
||||
});
|
||||
|
||||
it('dispatches fetchSecurityGroups action', () => {
|
||||
expect(securityGroupsActions.fetchItems).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ vpc, region },
|
||||
undefined,
|
||||
);
|
||||
expect(securityGroupsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), {
|
||||
vpc,
|
||||
region,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -539,7 +512,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setSubnet action', () => {
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet }, undefined);
|
||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -551,7 +524,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setRole action', () => {
|
||||
expect(actions.setRole).toHaveBeenCalledWith(expect.anything(), { role }, undefined);
|
||||
expect(actions.setRole).toHaveBeenCalledWith(expect.anything(), { role });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -563,7 +536,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setKeyPair action', () => {
|
||||
expect(actions.setKeyPair).toHaveBeenCalledWith(expect.anything(), { keyPair }, undefined);
|
||||
expect(actions.setKeyPair).toHaveBeenCalledWith(expect.anything(), { keyPair });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -575,11 +548,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setSecurityGroup action', () => {
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ securityGroup },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setSecurityGroup).toHaveBeenCalledWith(expect.anything(), { securityGroup });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -591,11 +560,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
});
|
||||
|
||||
it('dispatches setInstanceType action', () => {
|
||||
expect(actions.setInstanceType).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{ instanceType },
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setInstanceType).toHaveBeenCalledWith(expect.anything(), { instanceType });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -604,7 +569,7 @@ describe('EksClusterConfigurationForm', () => {
|
|||
|
||||
findNodeCountInput().vm.$emit('input', nodeCount);
|
||||
|
||||
expect(actions.setNodeCount).toHaveBeenCalledWith(expect.anything(), { nodeCount }, undefined);
|
||||
expect(actions.setNodeCount).toHaveBeenCalledWith(expect.anything(), { nodeCount });
|
||||
});
|
||||
|
||||
describe('when all cluster configuration fields are set', () => {
|
||||
|
|
|
|||
|
|
@ -124,11 +124,7 @@ describe('GkeMachineTypeDropdown', () => {
|
|||
wrapper.find('.dropdown-content button').trigger('click');
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(setMachineType).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
selectedMachineTypeMock,
|
||||
undefined,
|
||||
);
|
||||
expect(setMachineType).toHaveBeenCalledWith(expect.anything(), selectedMachineTypeMock);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -121,23 +121,19 @@ describe('GkeNetworkDropdown', () => {
|
|||
});
|
||||
|
||||
it('cleans selected subnetwork', () => {
|
||||
expect(setSubnetwork).toHaveBeenCalledWith(expect.anything(), '', undefined);
|
||||
expect(setSubnetwork).toHaveBeenCalledWith(expect.anything(), '');
|
||||
});
|
||||
|
||||
it('dispatches the setNetwork action', () => {
|
||||
expect(setNetwork).toHaveBeenCalledWith(expect.anything(), selectedNetwork, undefined);
|
||||
expect(setNetwork).toHaveBeenCalledWith(expect.anything(), selectedNetwork);
|
||||
});
|
||||
|
||||
it('fetches subnetworks for the selected project, region, and network', () => {
|
||||
expect(fetchSubnetworks).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
project: projectId,
|
||||
region,
|
||||
network: selectedNetwork.selfLink,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(fetchSubnetworks).toHaveBeenCalledWith(expect.anything(), {
|
||||
project: projectId,
|
||||
region,
|
||||
network: selectedNetwork.selfLink,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ describe('GkeProjectIdDropdown', () => {
|
|||
expect(setProject).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
gapiProjectsResponseMock.projects[0],
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ describe('GkeSubnetworkDropdown', () => {
|
|||
|
||||
wrapper.find(ClusterFormDropdown).vm.$emit('input', selectedSubnetwork);
|
||||
|
||||
expect(setSubnetwork).toHaveBeenCalledWith(expect.anything(), selectedSubnetwork, undefined);
|
||||
expect(setSubnetwork).toHaveBeenCalledWith(expect.anything(), selectedSubnetwork);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import { createMockClient } from 'mock-apollo-client';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import VueRouter from 'vue-router';
|
||||
import VueDraggable from 'vuedraggable';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import Design from '~/design_management/components/list/item.vue';
|
||||
import createRouter from '~/design_management/router';
|
||||
import getDesignListQuery from '~/design_management/graphql/queries/get_design_list.query.graphql';
|
||||
import permissionsQuery from '~/design_management/graphql/queries/design_permissions.query.graphql';
|
||||
import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql';
|
||||
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||||
import createMockApollo from '../../helpers/mock_apollo_helper';
|
||||
import Index from '~/design_management/pages/index.vue';
|
||||
import {
|
||||
designListQueryResponse,
|
||||
|
|
@ -39,8 +38,7 @@ const designToMove = {
|
|||
|
||||
describe('Design management index page with Apollo mock', () => {
|
||||
let wrapper;
|
||||
let mockClient;
|
||||
let apolloProvider;
|
||||
let fakeApollo;
|
||||
let moveDesignHandler;
|
||||
|
||||
async function moveDesigns(localWrapper) {
|
||||
|
|
@ -56,41 +54,23 @@ describe('Design management index page with Apollo mock', () => {
|
|||
});
|
||||
}
|
||||
|
||||
const fragmentMatcher = { match: () => true };
|
||||
|
||||
const cache = new InMemoryCache({
|
||||
fragmentMatcher,
|
||||
addTypename: false,
|
||||
});
|
||||
|
||||
const findDesigns = () => wrapper.findAll(Design);
|
||||
|
||||
function createComponent({
|
||||
moveHandler = jest.fn().mockResolvedValue(moveDesignMutationResponse),
|
||||
}) {
|
||||
mockClient = createMockClient({ cache });
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
getDesignListQuery,
|
||||
jest.fn().mockResolvedValue(designListQueryResponse),
|
||||
);
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
permissionsQuery,
|
||||
jest.fn().mockResolvedValue(permissionsQueryResponse),
|
||||
);
|
||||
|
||||
moveDesignHandler = moveHandler;
|
||||
|
||||
mockClient.setRequestHandler(moveDesignMutation, moveDesignHandler);
|
||||
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
const requestHandlers = [
|
||||
[getDesignListQuery, jest.fn().mockResolvedValue(designListQueryResponse)],
|
||||
[permissionsQuery, jest.fn().mockResolvedValue(permissionsQueryResponse)],
|
||||
[moveDesignMutation, moveDesignHandler],
|
||||
];
|
||||
|
||||
fakeApollo = createMockApollo(requestHandlers);
|
||||
wrapper = shallowMount(Index, {
|
||||
localVue,
|
||||
apolloProvider,
|
||||
apolloProvider: fakeApollo,
|
||||
router,
|
||||
stubs: { VueDraggable },
|
||||
});
|
||||
|
|
@ -99,8 +79,6 @@ describe('Design management index page with Apollo mock', () => {
|
|||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper = null;
|
||||
mockClient = null;
|
||||
apolloProvider = null;
|
||||
});
|
||||
|
||||
it('has a design with id 1 as a first one', async () => {
|
||||
|
|
@ -152,8 +130,9 @@ describe('Design management index page with Apollo mock', () => {
|
|||
|
||||
await moveDesigns(wrapper);
|
||||
|
||||
await jest.runOnlyPendingTimers();
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick(); // kick off the DOM update
|
||||
await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
|
||||
await wrapper.vm.$nextTick(); // kick off the DOM update for flash
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith(
|
||||
'Something went wrong when reordering designs. Please try again',
|
||||
|
|
|
|||
|
|
@ -177,23 +177,19 @@ describe('DiffContent', () => {
|
|||
});
|
||||
|
||||
wrapper.find(NoteForm).vm.$emit('handleFormUpdate', noteStub);
|
||||
expect(saveDiffDiscussionMock).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
note: noteStub,
|
||||
formData: {
|
||||
noteableData: expect.any(Object),
|
||||
diffFile: currentDiffFile,
|
||||
positionType: IMAGE_DIFF_POSITION_TYPE,
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
noteableType: undefined,
|
||||
},
|
||||
expect(saveDiffDiscussionMock).toHaveBeenCalledWith(expect.any(Object), {
|
||||
note: noteStub,
|
||||
formData: {
|
||||
noteableData: expect.any(Object),
|
||||
diffFile: currentDiffFile,
|
||||
positionType: IMAGE_DIFF_POSITION_TYPE,
|
||||
x: undefined,
|
||||
y: undefined,
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
noteableType: undefined,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
|
||||
import EditButton from '~/diffs/components/edit_button.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
|
|
@ -26,12 +27,16 @@ const diffFile = Object.freeze(
|
|||
}),
|
||||
);
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
||||
describe('DiffFileHeader component', () => {
|
||||
let wrapper;
|
||||
let mockStoreConfig;
|
||||
|
||||
const diffHasExpandedDiscussionsResultMock = jest.fn();
|
||||
const diffHasDiscussionsResultMock = jest.fn();
|
||||
const mockStoreConfig = {
|
||||
const defaultMockStoreConfig = {
|
||||
state: {},
|
||||
modules: {
|
||||
diffs: {
|
||||
|
|
@ -56,6 +61,8 @@ describe('DiffFileHeader component', () => {
|
|||
diffHasExpandedDiscussionsResultMock,
|
||||
...Object.values(mockStoreConfig.modules.diffs.actions),
|
||||
].forEach(mock => mock.mockReset());
|
||||
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findHeader = () => wrapper.find({ ref: 'header' });
|
||||
|
|
@ -80,8 +87,7 @@ describe('DiffFileHeader component', () => {
|
|||
};
|
||||
|
||||
const createComponent = props => {
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
mockStoreConfig = cloneDeep(defaultMockStoreConfig);
|
||||
const store = new Vuex.Store(mockStoreConfig);
|
||||
|
||||
wrapper = shallowMount(DiffFileHeader, {
|
||||
|
|
@ -286,7 +292,7 @@ describe('DiffFileHeader component', () => {
|
|||
findToggleDiscussionsButton().vm.$emit('click');
|
||||
expect(
|
||||
mockStoreConfig.modules.diffs.actions.toggleFileDiscussionWrappers,
|
||||
).toHaveBeenCalledWith(expect.any(Object), diffFile, undefined);
|
||||
).toHaveBeenCalledWith(expect.any(Object), diffFile);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ describe('Diff settings dropdown component', () => {
|
|||
|
||||
vm.find('.js-list-view').trigger('click');
|
||||
|
||||
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false, undefined);
|
||||
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false);
|
||||
});
|
||||
|
||||
it('tree view button dispatches setRenderTreeList with true', () => {
|
||||
|
|
@ -58,7 +58,7 @@ describe('Diff settings dropdown component', () => {
|
|||
|
||||
vm.find('.js-tree-view').trigger('click');
|
||||
|
||||
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true, undefined);
|
||||
expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true);
|
||||
});
|
||||
|
||||
it('sets list button as selected when renderTreeList is false', () => {
|
||||
|
|
@ -153,14 +153,10 @@ describe('Diff settings dropdown component', () => {
|
|||
checkbox.element.checked = true;
|
||||
checkbox.trigger('change');
|
||||
|
||||
expect(actions.setShowWhitespace).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
showWhitespace: true,
|
||||
pushState: true,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.setShowWhitespace).toHaveBeenCalledWith(expect.anything(), {
|
||||
showWhitespace: true,
|
||||
pushState: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -259,23 +259,15 @@ describe('ErrorTrackingList', () => {
|
|||
errorId: errorsList[0].id,
|
||||
status: 'ignored',
|
||||
});
|
||||
expect(actions.updateStatus).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`,
|
||||
status: 'ignored',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.updateStatus).toHaveBeenCalledWith(expect.anything(), {
|
||||
endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`,
|
||||
status: 'ignored',
|
||||
});
|
||||
});
|
||||
|
||||
it('calls an action to remove the item from the list', () => {
|
||||
findErrorActions().vm.$emit('update-issue-status', { errorId: '1', status: undefined });
|
||||
expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
'1',
|
||||
undefined,
|
||||
);
|
||||
expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith(expect.anything(), '1');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -298,23 +290,15 @@ describe('ErrorTrackingList', () => {
|
|||
errorId: errorsList[0].id,
|
||||
status: 'resolved',
|
||||
});
|
||||
expect(actions.updateStatus).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`,
|
||||
status: 'resolved',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.updateStatus).toHaveBeenCalledWith(expect.anything(), {
|
||||
endpoint: `/project/test/-/error_tracking/${errorsList[0].id}.json`,
|
||||
status: 'resolved',
|
||||
});
|
||||
});
|
||||
|
||||
it('calls an action to remove the item from the list', () => {
|
||||
findErrorActions().vm.$emit('update-issue-status', { errorId: '1', status: undefined });
|
||||
expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
'1',
|
||||
undefined,
|
||||
);
|
||||
expect(actions.removeIgnoredResolvedErrors).toHaveBeenCalledWith(expect.anything(), '1');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -443,7 +427,6 @@ describe('ErrorTrackingList', () => {
|
|||
expect(actions.fetchPaginatedResults).toHaveBeenLastCalledWith(
|
||||
expect.anything(),
|
||||
'previousCursor',
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -462,7 +445,6 @@ describe('ErrorTrackingList', () => {
|
|||
expect(actions.fetchPaginatedResults).toHaveBeenLastCalledWith(
|
||||
expect.anything(),
|
||||
'nextCursor',
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import { createMockClient } from 'mock-apollo-client';
|
||||
import VueApollo from 'vue-apollo';
|
||||
|
||||
export default (handlers = []) => {
|
||||
const fragmentMatcher = { match: () => true };
|
||||
const cache = new InMemoryCache({
|
||||
fragmentMatcher,
|
||||
addTypename: false,
|
||||
});
|
||||
|
||||
const mockClient = createMockClient({ cache });
|
||||
|
||||
if (Array.isArray(handlers)) {
|
||||
handlers.forEach(([query, value]) => mockClient.setRequestHandler(query, value));
|
||||
} else {
|
||||
throw new Error('You should pass an array of handlers to mock Apollo client');
|
||||
}
|
||||
|
||||
const apolloProvider = new VueApollo({ defaultClient: mockClient });
|
||||
|
||||
return apolloProvider;
|
||||
};
|
||||
|
|
@ -51,7 +51,7 @@ describe('IDE error message component', () => {
|
|||
createComponent();
|
||||
findDismissButton().trigger('click');
|
||||
|
||||
expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null, undefined);
|
||||
expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null);
|
||||
});
|
||||
|
||||
describe('with action', () => {
|
||||
|
|
|
|||
|
|
@ -99,11 +99,7 @@ describe('IDE stages list', () => {
|
|||
it('calls toggleStageCollapsed when clicking stage header', () => {
|
||||
findCardHeader().trigger('click');
|
||||
|
||||
expect(storeActions.toggleStageCollapsed).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
0,
|
||||
undefined,
|
||||
);
|
||||
expect(storeActions.toggleStageCollapsed).toHaveBeenCalledWith(expect.any(Object), 0);
|
||||
});
|
||||
|
||||
it('calls fetchJobs when stage is mounted', () => {
|
||||
|
|
|
|||
|
|
@ -56,14 +56,10 @@ describe('IDE merge requests list', () => {
|
|||
|
||||
it('calls fetch on mounted', () => {
|
||||
createComponent();
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
search: '',
|
||||
type: '',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(expect.any(Object), {
|
||||
search: '',
|
||||
type: '',
|
||||
});
|
||||
});
|
||||
|
||||
it('renders loading icon when merge request is loading', () => {
|
||||
|
|
@ -95,14 +91,10 @@ describe('IDE merge requests list', () => {
|
|||
const searchType = wrapper.vm.$options.searchTypes[0];
|
||||
|
||||
expect(findTokenedInput().props('tokens')).toEqual([searchType]);
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
type: searchType.type,
|
||||
search: '',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(expect.any(Object), {
|
||||
type: searchType.type,
|
||||
search: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -136,14 +128,10 @@ describe('IDE merge requests list', () => {
|
|||
input.vm.$emit('input', 'something');
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
search: 'something',
|
||||
type: '',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(fetchMergeRequestsMock).toHaveBeenCalledWith(expect.any(Object), {
|
||||
search: 'something',
|
||||
type: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -279,24 +279,16 @@ describe('IDE clientside preview', () => {
|
|||
});
|
||||
|
||||
it('calls getFileData', () => {
|
||||
expect(storeActions.getFileData).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
path: 'package.json',
|
||||
makeFileActive: false,
|
||||
},
|
||||
undefined, // vuex callback
|
||||
);
|
||||
expect(storeActions.getFileData).toHaveBeenCalledWith(expect.any(Object), {
|
||||
path: 'package.json',
|
||||
makeFileActive: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('calls getRawFileData', () => {
|
||||
expect(storeActions.getRawFileData).toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
{
|
||||
path: 'package.json',
|
||||
},
|
||||
undefined, // vuex callback
|
||||
);
|
||||
expect(storeActions.getRawFileData).toHaveBeenCalledWith(expect.any(Object), {
|
||||
path: 'package.json',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { serializeForm } from '~/lib/utils/forms';
|
||||
import { serializeForm, serializeFormObject, isEmptyValue } from '~/lib/utils/forms';
|
||||
|
||||
describe('lib/utils/forms', () => {
|
||||
const createDummyForm = inputs => {
|
||||
|
|
@ -93,4 +93,46 @@ describe('lib/utils/forms', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEmptyValue', () => {
|
||||
it.each`
|
||||
input | returnValue
|
||||
${''} | ${true}
|
||||
${[]} | ${true}
|
||||
${null} | ${true}
|
||||
${undefined} | ${true}
|
||||
${'hello'} | ${false}
|
||||
${' '} | ${false}
|
||||
${0} | ${false}
|
||||
`('returns $returnValue for value $input', ({ input, returnValue }) => {
|
||||
expect(isEmptyValue(input)).toBe(returnValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('serializeFormObject', () => {
|
||||
it('returns an serialized object', () => {
|
||||
const form = {
|
||||
profileName: { value: 'hello', state: null, feedback: null },
|
||||
spiderTimeout: { value: 2, state: true, feedback: null },
|
||||
targetTimeout: { value: 12, state: true, feedback: null },
|
||||
};
|
||||
expect(serializeFormObject(form)).toEqual({
|
||||
profileName: 'hello',
|
||||
spiderTimeout: 2,
|
||||
targetTimeout: 12,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns only the entries with value', () => {
|
||||
const form = {
|
||||
profileName: { value: '', state: null, feedback: null },
|
||||
spiderTimeout: { value: 0, state: null, feedback: null },
|
||||
targetTimeout: { value: null, state: null, feedback: null },
|
||||
name: { value: undefined, state: null, feedback: null },
|
||||
};
|
||||
expect(serializeFormObject(form)).toEqual({
|
||||
spiderTimeout: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import resolveDiscussionButton from '~/notes/components/discussion_resolve_button.vue';
|
||||
|
||||
const buttonTitle = 'Resolve discussion';
|
||||
|
|
@ -26,9 +27,9 @@ describe('resolveDiscussionButton', () => {
|
|||
});
|
||||
|
||||
it('should emit a onClick event on button click', () => {
|
||||
const button = wrapper.find({ ref: 'button' });
|
||||
const button = wrapper.find(GlButton);
|
||||
|
||||
button.trigger('click');
|
||||
button.vm.$emit('click');
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.emitted()).toEqual({
|
||||
|
|
@ -38,7 +39,7 @@ describe('resolveDiscussionButton', () => {
|
|||
});
|
||||
|
||||
it('should contain the provided button title', () => {
|
||||
const button = wrapper.find({ ref: 'button' });
|
||||
const button = wrapper.find(GlButton);
|
||||
|
||||
expect(button.text()).toContain(buttonTitle);
|
||||
});
|
||||
|
|
@ -51,9 +52,9 @@ describe('resolveDiscussionButton', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const button = wrapper.find({ ref: 'isResolvingIcon' });
|
||||
const button = wrapper.find(GlButton);
|
||||
|
||||
expect(button.exists()).toEqual(true);
|
||||
expect(button.props('loading')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should only show a loading spinner while resolving', () => {
|
||||
|
|
@ -64,10 +65,10 @@ describe('resolveDiscussionButton', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const button = wrapper.find({ ref: 'isResolvingIcon' });
|
||||
const button = wrapper.find(GlButton);
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(button.exists()).toEqual(false);
|
||||
expect(button.props('loading')).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -194,13 +194,9 @@ describe('Discussion navigation mixin', () => {
|
|||
});
|
||||
|
||||
it('expands discussion', () => {
|
||||
expect(expandDiscussion).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
discussionId: expected,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(expandDiscussion).toHaveBeenCalledWith(expect.anything(), {
|
||||
discussionId: expected,
|
||||
});
|
||||
});
|
||||
|
||||
it('scrolls to discussion', () => {
|
||||
|
|
|
|||
|
|
@ -133,11 +133,7 @@ describe('Author Select', () => {
|
|||
const authorName = 'lorem';
|
||||
findSearchBox().vm.$emit('input', authorName);
|
||||
|
||||
expect(store.actions.fetchAuthors).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
authorName,
|
||||
undefined,
|
||||
);
|
||||
expect(store.actions.fetchAuthors).toHaveBeenCalledWith(expect.anything(), authorName);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -115,14 +115,10 @@ describe('Release edit component', () => {
|
|||
|
||||
const expectStoreMethodToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newUrl,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith(expect.anything(), {
|
||||
linkIdToUpdate,
|
||||
newUrl,
|
||||
});
|
||||
};
|
||||
|
||||
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => {
|
||||
|
|
@ -177,14 +173,10 @@ describe('Release edit component', () => {
|
|||
|
||||
const expectStoreMethodToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newName,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledWith(expect.anything(), {
|
||||
linkIdToUpdate,
|
||||
newName,
|
||||
});
|
||||
};
|
||||
|
||||
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => {
|
||||
|
|
@ -225,14 +217,10 @@ describe('Release edit component', () => {
|
|||
wrapper.find({ ref: 'typeSelect' }).vm.$emit('change', newType);
|
||||
|
||||
expect(actions.updateAssetLinkType).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkType).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newType,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(actions.updateAssetLinkType).toHaveBeenCalledWith(expect.anything(), {
|
||||
linkIdToUpdate,
|
||||
newType,
|
||||
});
|
||||
});
|
||||
|
||||
it('selects the default asset type if no type was provided by the backend', () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { setHTMLFixture } from './helpers/fixtures';
|
||||
import Tracking, { initUserTracking } from '~/tracking';
|
||||
import Tracking, { initUserTracking, initDefaultTrackers } from '~/tracking';
|
||||
|
||||
describe('Tracking', () => {
|
||||
let snowplowSpy;
|
||||
|
|
@ -17,11 +17,6 @@ describe('Tracking', () => {
|
|||
});
|
||||
|
||||
describe('initUserTracking', () => {
|
||||
beforeEach(() => {
|
||||
bindDocumentSpy = jest.spyOn(Tracking, 'bindDocument').mockImplementation(() => null);
|
||||
trackLoadEventsSpy = jest.spyOn(Tracking, 'trackLoadEvents').mockImplementation(() => null);
|
||||
});
|
||||
|
||||
it('calls through to get a new tracker with the expected options', () => {
|
||||
initUserTracking();
|
||||
expect(snowplowSpy).toHaveBeenCalledWith('newTracker', '_namespace_', 'app.gitfoo.com', {
|
||||
|
|
@ -38,9 +33,16 @@ describe('Tracking', () => {
|
|||
linkClickTracking: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('initDefaultTrackers', () => {
|
||||
beforeEach(() => {
|
||||
bindDocumentSpy = jest.spyOn(Tracking, 'bindDocument').mockImplementation(() => null);
|
||||
trackLoadEventsSpy = jest.spyOn(Tracking, 'trackLoadEvents').mockImplementation(() => null);
|
||||
});
|
||||
|
||||
it('should activate features based on what has been enabled', () => {
|
||||
initUserTracking();
|
||||
initDefaultTrackers();
|
||||
expect(snowplowSpy).toHaveBeenCalledWith('enableActivityTracking', 30, 30);
|
||||
expect(snowplowSpy).toHaveBeenCalledWith('trackPageView');
|
||||
expect(snowplowSpy).not.toHaveBeenCalledWith('enableFormTracking');
|
||||
|
|
@ -52,18 +54,18 @@ describe('Tracking', () => {
|
|||
linkClickTracking: true,
|
||||
};
|
||||
|
||||
initUserTracking();
|
||||
initDefaultTrackers();
|
||||
expect(snowplowSpy).toHaveBeenCalledWith('enableFormTracking');
|
||||
expect(snowplowSpy).toHaveBeenCalledWith('enableLinkClickTracking');
|
||||
});
|
||||
|
||||
it('binds the document event handling', () => {
|
||||
initUserTracking();
|
||||
initDefaultTrackers();
|
||||
expect(bindDocumentSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('tracks page loaded events', () => {
|
||||
initUserTracking();
|
||||
initDefaultTrackers();
|
||||
expect(trackLoadEventsSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
|
|||
|
||||
let(:command) do
|
||||
double(:command,
|
||||
config_processor: double(:processor,
|
||||
yaml_processor_result: double(:processor,
|
||||
jobs: { echo: double(:job_echo), rspec: double(:job_rspec) }),
|
||||
project: project,
|
||||
chat_data: { command: 'echo' })
|
||||
|
|
@ -25,7 +25,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
|
|||
|
||||
subject
|
||||
|
||||
expect(command.config_processor.jobs.keys).to eq([:echo])
|
||||
expect(command.yaml_processor_result.jobs.keys).to eq([:echo])
|
||||
end
|
||||
|
||||
it 'does not remove any jobs for non chat-pipelines' do
|
||||
|
|
@ -33,7 +33,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
|
|||
|
||||
subject
|
||||
|
||||
expect(command.config_processor.jobs.keys).to eq([:echo, :rspec])
|
||||
expect(command.yaml_processor_result.jobs.keys).to eq([:echo, :rspec])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
|
|||
let(:save_incompleted) { true }
|
||||
let(:command) do
|
||||
Gitlab::Ci::Pipeline::Chain::Command.new(
|
||||
project: project, current_user: user, config_processor: yaml_processor_result, save_incompleted: save_incompleted
|
||||
project: project, current_user: user, yaml_processor_result: yaml_processor_result, save_incompleted: save_incompleted
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
|
|||
end
|
||||
|
||||
describe '#validation_service_payload' do
|
||||
subject(:validation_service_payload) { step.send(:validation_service_payload, pipeline, command.config_processor.stages_attributes) }
|
||||
subject(:validation_service_payload) { step.send(:validation_service_payload, pipeline, command.yaml_processor_result.stages_attributes) }
|
||||
|
||||
it 'respects the defined schema' do
|
||||
expect(validation_service_payload).to match_schema('/external_validation')
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ RSpec.describe ProjectBadge do
|
|||
end
|
||||
|
||||
context 'methods' do
|
||||
let(:badge) { build(:project_badge, link_url: placeholder_url, image_url: placeholder_url) }
|
||||
let!(:project) { badge.project }
|
||||
let(:badge) { build_stubbed(:project_badge, link_url: placeholder_url, image_url: placeholder_url) }
|
||||
let(:project) { badge.project }
|
||||
|
||||
describe '#rendered_link_url' do
|
||||
let(:method) { :link_url }
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ RSpec.describe DiffNote do
|
|||
subject { create(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request) }
|
||||
|
||||
describe 'validations' do
|
||||
it_behaves_like 'a valid diff positionable note', :diff_note_on_commit
|
||||
it_behaves_like 'a valid diff positionable note' do
|
||||
subject { build(:diff_note_on_commit, project: project, commit_id: commit_id, position: position) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#position=" do
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue