Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b9bc4d88ea
commit
ab15b68754
|
@ -1,9 +1,11 @@
|
|||
import $ from 'jquery';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import Mousetrap from 'mousetrap';
|
||||
import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard';
|
||||
import { getSelectedFragment } from '~/lib/utils/common_utils';
|
||||
import { isElementVisible } from '~/lib/utils/dom_utils';
|
||||
import { DEBOUNCE_DROPDOWN_DELAY } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
|
||||
import toast from '~/vue_shared/plugins/global_toast';
|
||||
import { s__ } from '~/locale';
|
||||
import Sidebar from '~/right_sidebar';
|
||||
import { CopyAsGFM } from '../markdown/copy_as_gfm';
|
||||
import {
|
||||
|
@ -21,6 +23,15 @@ export default class ShortcutsIssuable extends Shortcuts {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.inMemoryButton = document.createElement('button');
|
||||
this.clipboardInstance = new ClipboardJS(this.inMemoryButton);
|
||||
this.clipboardInstance.on('success', () => {
|
||||
toast(s__('GlobalShortcuts|Copied source branch name to clipboard.'));
|
||||
});
|
||||
this.clipboardInstance.on('error', () => {
|
||||
toast(s__('GlobalShortcuts|Unable to copy the source branch name at this time.'));
|
||||
});
|
||||
|
||||
Mousetrap.bind(keysFor(ISSUE_MR_CHANGE_ASSIGNEE), () =>
|
||||
ShortcutsIssuable.openSidebarDropdown('assignee'),
|
||||
);
|
||||
|
@ -32,7 +43,7 @@ export default class ShortcutsIssuable extends Shortcuts {
|
|||
);
|
||||
Mousetrap.bind(keysFor(ISSUABLE_COMMENT_OR_REPLY), ShortcutsIssuable.replyWithSelectedText);
|
||||
Mousetrap.bind(keysFor(ISSUABLE_EDIT_DESCRIPTION), ShortcutsIssuable.editIssue);
|
||||
Mousetrap.bind(keysFor(MR_COPY_SOURCE_BRANCH_NAME), ShortcutsIssuable.copyBranchName);
|
||||
Mousetrap.bind(keysFor(MR_COPY_SOURCE_BRANCH_NAME), () => this.copyBranchName());
|
||||
|
||||
/**
|
||||
* We're attaching a global focus event listener on document for
|
||||
|
@ -153,17 +164,14 @@ export default class ShortcutsIssuable extends Shortcuts {
|
|||
return false;
|
||||
}
|
||||
|
||||
static copyBranchName() {
|
||||
// There are two buttons - one that is shown when the sidebar
|
||||
// is expanded, and one that is shown when it's collapsed.
|
||||
const allCopyBtns = Array.from(document.querySelectorAll('.js-source-branch-copy'));
|
||||
async copyBranchName() {
|
||||
const button = document.querySelector('.js-source-branch-copy');
|
||||
const branchName = button?.dataset.clipboardText;
|
||||
|
||||
// Select whichever button is currently visible so that
|
||||
// the "Copied" tooltip is shown when a click is simulated.
|
||||
const visibleBtn = allCopyBtns.find(isElementVisible);
|
||||
if (branchName) {
|
||||
this.inMemoryButton.dataset.clipboardText = branchName;
|
||||
|
||||
if (visibleBtn) {
|
||||
clickCopyToClipboardButton(visibleBtn);
|
||||
this.inMemoryButton.dispatchEvent(new CustomEvent('click'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,21 +48,12 @@ export default {
|
|||
listHasNextPage() {
|
||||
return this.pageInfoByListId[this.list.id]?.hasNextPage;
|
||||
},
|
||||
firstItemInListId() {
|
||||
return this.listItems[0]?.id;
|
||||
},
|
||||
lengthOfListItemsInBoard() {
|
||||
return this.listItems?.length;
|
||||
},
|
||||
lastItemInTheListId() {
|
||||
return this.listItems[this.lengthOfListItemsInBoard - 1]?.id;
|
||||
},
|
||||
itemIdentifier() {
|
||||
return `${this.item.id}-${this.item.iid}-${this.index}`;
|
||||
},
|
||||
showMoveToEndOfList() {
|
||||
return !this.listHasNextPage;
|
||||
},
|
||||
isFirstItemInList() {
|
||||
return this.index === 0;
|
||||
},
|
||||
|
@ -80,9 +71,8 @@ export default {
|
|||
if (this.isFirstItemInList) {
|
||||
return;
|
||||
}
|
||||
const moveAfterId = this.firstItemInListId;
|
||||
this.moveToPosition({
|
||||
moveAfterId,
|
||||
positionInList: 0,
|
||||
});
|
||||
},
|
||||
moveToEnd() {
|
||||
|
@ -93,20 +83,20 @@ export default {
|
|||
if (this.isLastItemInList) {
|
||||
return;
|
||||
}
|
||||
const moveBeforeId = this.lastItemInTheListId;
|
||||
this.moveToPosition({
|
||||
moveBeforeId,
|
||||
positionInList: -1,
|
||||
});
|
||||
},
|
||||
moveToPosition({ moveAfterId, moveBeforeId }) {
|
||||
moveToPosition({ positionInList }) {
|
||||
this.moveItem({
|
||||
itemId: this.item.id,
|
||||
itemIid: this.item.iid,
|
||||
itemPath: this.item.referencePath,
|
||||
fromListId: this.list.id,
|
||||
toListId: this.list.id,
|
||||
moveAfterId,
|
||||
moveBeforeId,
|
||||
positionInList,
|
||||
atIndex: this.index,
|
||||
allItemsLoadedInList: !this.listHasNextPage,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
@ -117,7 +107,6 @@ export default {
|
|||
<gl-dropdown
|
||||
ref="dropdown"
|
||||
:key="itemIdentifier"
|
||||
data-testid="move-card-dropdown"
|
||||
icon="ellipsis_v"
|
||||
:text="s__('Boards|Move card')"
|
||||
:text-sr-only="true"
|
||||
|
@ -128,14 +117,10 @@ export default {
|
|||
@keydown.esc.native="$emit('hide')"
|
||||
>
|
||||
<div>
|
||||
<gl-dropdown-item data-testid="action-move-to-first" @click.stop="moveToStart">
|
||||
<gl-dropdown-item @click.stop="moveToStart">
|
||||
{{ $options.i18n.moveToStartText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item
|
||||
v-if="showMoveToEndOfList"
|
||||
data-testid="action-move-to-end"
|
||||
@click.stop="moveToEnd"
|
||||
>
|
||||
<gl-dropdown-item @click.stop="moveToEnd">
|
||||
{{ $options.i18n.moveToEndText }}
|
||||
</gl-dropdown-item>
|
||||
</div>
|
||||
|
|
|
@ -66,7 +66,7 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['pageInfoByListId', 'listsFlags', 'filterParams']),
|
||||
...mapState(['pageInfoByListId', 'listsFlags', 'filterParams', 'isUpdateIssueOrderInProgress']),
|
||||
...mapGetters(['isEpicBoard']),
|
||||
listItemsCount() {
|
||||
return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount;
|
||||
|
@ -132,6 +132,9 @@ export default {
|
|||
|
||||
return this.canMoveIssue ? options : {};
|
||||
},
|
||||
disableScrollingWhenMutationInProgress() {
|
||||
return this.hasNextPage && this.isUpdateIssueOrderInProgress;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
boardItems() {
|
||||
|
@ -285,9 +288,13 @@ export default {
|
|||
v-bind="treeRootOptions"
|
||||
:data-board="list.id"
|
||||
:data-board-type="list.listType"
|
||||
:class="{ 'bg-danger-100': boardItemsSizeExceedsMax }"
|
||||
:class="{
|
||||
'bg-danger-100': boardItemsSizeExceedsMax,
|
||||
'gl-overflow-hidden': disableScrollingWhenMutationInProgress,
|
||||
'gl-overflow-y-auto': !disableScrollingWhenMutationInProgress,
|
||||
}"
|
||||
draggable=".board-card"
|
||||
class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-3 gl-pt-0 gl-overflow-y-auto gl-overflow-x-hidden"
|
||||
class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-3 gl-pt-0 gl-overflow-x-hidden"
|
||||
data-testid="tree-root-wrapper"
|
||||
@start="handleDragOnStart"
|
||||
@end="handleDragOnEnd"
|
||||
|
|
|
@ -479,16 +479,25 @@ export default {
|
|||
toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
positionInList,
|
||||
allItemsLoadedInList,
|
||||
} = moveData;
|
||||
|
||||
commit(types.REMOVE_BOARD_ITEM_FROM_LIST, { itemId, listId: fromListId });
|
||||
|
||||
if (reordering && !allItemsLoadedInList && positionInList === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reordering) {
|
||||
commit(types.ADD_BOARD_ITEM_TO_LIST, {
|
||||
itemId,
|
||||
listId: toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
positionInList,
|
||||
atIndex: originalIndex,
|
||||
allItemsLoadedInList,
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -500,6 +509,7 @@ export default {
|
|||
listId: toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
positionInList,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -553,7 +563,15 @@ export default {
|
|||
|
||||
updateIssueOrder: async ({ commit, dispatch, state }, { moveData, mutationVariables = {} }) => {
|
||||
try {
|
||||
const { itemId, fromListId, toListId, moveBeforeId, moveAfterId, itemNotInToList } = moveData;
|
||||
const {
|
||||
itemId,
|
||||
fromListId,
|
||||
toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
itemNotInToList,
|
||||
positionInList,
|
||||
} = moveData;
|
||||
const {
|
||||
fullBoardId,
|
||||
filterParams,
|
||||
|
@ -562,6 +580,8 @@ export default {
|
|||
},
|
||||
} = state;
|
||||
|
||||
commit(types.MUTATE_ISSUE_IN_PROGRESS, true);
|
||||
|
||||
const { data } = await gqlClient.mutate({
|
||||
mutation: issueMoveListMutation,
|
||||
variables: {
|
||||
|
@ -572,6 +592,7 @@ export default {
|
|||
toListId: getIdFromGraphQLId(toListId),
|
||||
moveBeforeId: moveBeforeId ? getIdFromGraphQLId(moveBeforeId) : undefined,
|
||||
moveAfterId: moveAfterId ? getIdFromGraphQLId(moveAfterId) : undefined,
|
||||
positionInList,
|
||||
// 'mutationVariables' allows EE code to pass in extra parameters.
|
||||
...mutationVariables,
|
||||
},
|
||||
|
@ -643,7 +664,9 @@ export default {
|
|||
}
|
||||
|
||||
commit(types.MUTATE_ISSUE_SUCCESS, { issue: data.issueMoveList.issue });
|
||||
commit(types.MUTATE_ISSUE_IN_PROGRESS, false);
|
||||
} catch {
|
||||
commit(types.MUTATE_ISSUE_IN_PROGRESS, false);
|
||||
commit(
|
||||
types.SET_ERROR,
|
||||
s__('Boards|An error occurred while moving the issue. Please try again.'),
|
||||
|
|
|
@ -44,3 +44,4 @@ export const ADD_LIST_TO_HIGHLIGHTED_LISTS = 'ADD_LIST_TO_HIGHLIGHTED_LISTS';
|
|||
export const REMOVE_LIST_FROM_HIGHLIGHTED_LISTS = 'REMOVE_LIST_FROM_HIGHLIGHTED_LISTS';
|
||||
export const RESET_BOARD_ITEM_SELECTION = 'RESET_BOARD_ITEM_SELECTION';
|
||||
export const SET_ERROR = 'SET_ERROR';
|
||||
export const MUTATE_ISSUE_IN_PROGRESS = 'MUTATE_ISSUE_IN_PROGRESS';
|
||||
|
|
|
@ -20,17 +20,28 @@ export const removeItemFromList = ({ state, listId, itemId }) => {
|
|||
updateListItemsCount({ state, listId, value: -1 });
|
||||
};
|
||||
|
||||
export const addItemToList = ({ state, listId, itemId, moveBeforeId, moveAfterId, atIndex }) => {
|
||||
export const addItemToList = ({
|
||||
state,
|
||||
listId,
|
||||
itemId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
atIndex,
|
||||
positionInList,
|
||||
}) => {
|
||||
const listIssues = state.boardItemsByListId[listId];
|
||||
let newIndex = atIndex || 0;
|
||||
const moveToStartOrLast = positionInList !== undefined;
|
||||
if (moveBeforeId) {
|
||||
newIndex = listIssues.indexOf(moveBeforeId) + 1;
|
||||
} else if (moveAfterId) {
|
||||
newIndex = listIssues.indexOf(moveAfterId);
|
||||
} else if (moveToStartOrLast) {
|
||||
newIndex = positionInList === -1 ? listIssues.length : 0;
|
||||
}
|
||||
listIssues.splice(newIndex, 0, itemId);
|
||||
Vue.set(state.boardItemsByListId, listId, listIssues);
|
||||
updateListItemsCount({ state, listId, value: 1 });
|
||||
updateListItemsCount({ state, listId, value: moveToStartOrLast ? 0 : 1 });
|
||||
};
|
||||
|
||||
export default {
|
||||
|
@ -205,12 +216,34 @@ export default {
|
|||
Vue.set(state.boardItems, issue.id, formatIssue(issue));
|
||||
},
|
||||
|
||||
[mutationTypes.MUTATE_ISSUE_IN_PROGRESS](state, isLoading) {
|
||||
state.isUpdateIssueOrderInProgress = isLoading;
|
||||
},
|
||||
|
||||
[mutationTypes.ADD_BOARD_ITEM_TO_LIST]: (
|
||||
state,
|
||||
{ itemId, listId, moveBeforeId, moveAfterId, atIndex, inProgress = false },
|
||||
{
|
||||
itemId,
|
||||
listId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
atIndex,
|
||||
positionInList,
|
||||
allItemsLoadedInList,
|
||||
inProgress = false,
|
||||
},
|
||||
) => {
|
||||
Vue.set(state.listsFlags, listId, { ...state.listsFlags, addItemToListInProgress: inProgress });
|
||||
addItemToList({ state, listId, itemId, moveBeforeId, moveAfterId, atIndex });
|
||||
addItemToList({
|
||||
state,
|
||||
listId,
|
||||
itemId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
atIndex,
|
||||
positionInList,
|
||||
allItemsLoadedInList,
|
||||
});
|
||||
},
|
||||
|
||||
[mutationTypes.REMOVE_BOARD_ITEM_FROM_LIST]: (state, { itemId, listId }) => {
|
||||
|
|
|
@ -40,4 +40,5 @@ export default () => ({
|
|||
},
|
||||
// TODO: remove after ce/ee split of board_content.vue
|
||||
isShowingEpicsSwimlanes: false,
|
||||
isUpdateIssueOrderInProgress: false,
|
||||
});
|
||||
|
|
|
@ -77,7 +77,7 @@ module Ci
|
|||
%i[pipeline project ref tag options name
|
||||
allow_failure stage stage_idx
|
||||
yaml_variables when description needs_attributes
|
||||
scheduling_type ci_stage].freeze
|
||||
scheduling_type ci_stage partition_id].freeze
|
||||
end
|
||||
|
||||
def inherit_status_from_downstream!(pipeline)
|
||||
|
|
|
@ -217,7 +217,8 @@ module Ci
|
|||
allow_failure stage stage_idx trigger_request
|
||||
yaml_variables when environment coverage_regex
|
||||
description tag_list protected needs_attributes
|
||||
job_variables_attributes resource_group scheduling_type ci_stage].freeze
|
||||
job_variables_attributes resource_group scheduling_type
|
||||
ci_stage partition_id].freeze
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
class Partition < Ci::ApplicationRecord
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
- form = local_assigns.fetch(:form)
|
||||
.form-group
|
||||
= form.label :notification_email, class: "label-bold"
|
||||
= form.label :notification_email, _('Notification Email'), class: "label-bold"
|
||||
= form.select :notification_email, @user.public_verified_emails, { include_blank: _('Use primary email (%{email})') % { email: @user.email }, selected: @user.notification_email }, class: "select2", disabled: local_assigns.fetch(:email_change_disabled, nil)
|
||||
.help-block
|
||||
= local_assigns.fetch(:help_text, nil)
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
= gitlab_ui_form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications gl-mt-3' } do |f|
|
||||
= render_if_exists 'profiles/notifications/email_settings', form: f
|
||||
|
||||
= label_tag :global_notification_level, "Global notification level", class: "label-bold"
|
||||
= label_tag :global_notification_level, _('Global notification level'), class: "label-bold"
|
||||
%br
|
||||
.clearfix
|
||||
.form-group.float-left.global-notification-setting
|
||||
|
|
|
@ -12,7 +12,7 @@ time_frame: all
|
|||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
counter_class: SourceCodeCounter
|
||||
prefix: source_code
|
||||
event: pushes
|
||||
distribution:
|
||||
- ce
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
table_name: ci_partitions
|
||||
classes:
|
||||
- Ci::Partition
|
||||
feature_categories:
|
||||
- continuous_integration
|
||||
description: Database partitioning metadata for CI tables
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96856
|
||||
milestone: '15.4'
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateCiPartitions < Gitlab::Database::Migration[2.0]
|
||||
def change
|
||||
create_table :ci_partitions do |t|
|
||||
t.timestamps_with_timezone null: false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateDefaultPartitionRecord < Gitlab::Database::Migration[2.0]
|
||||
disable_ddl_transaction!
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
def up
|
||||
execute(<<~SQL)
|
||||
INSERT INTO "ci_partitions" ("id", "created_at", "updated_at")
|
||||
VALUES (100, now(), now());
|
||||
SQL
|
||||
|
||||
reset_pk_sequence!('ci_partitions')
|
||||
end
|
||||
|
||||
def down
|
||||
execute(<<~SQL)
|
||||
DELETE FROM "ci_partitions" WHERE "ci_partitions"."id" = 100;
|
||||
SQL
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiBuilds < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
# rubocop:disable Migration/AddColumnsToWideTables
|
||||
def change
|
||||
add_column :ci_builds, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
# rubocop:enable Migration/AddColumnsToWideTables
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiBuildsMetadata < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :ci_builds_metadata, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiJobArtifacts < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :ci_job_artifacts, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiPipelines < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :ci_pipelines, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiStages < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :ci_stages, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddPartitionIdToCiPipelineVariables < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
add_column :ci_pipeline_variables, :partition_id, :bigint, default: 100, null: false
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
d1ca445a17c742d435cba3d898e61242a3df9c92caeadecba147fce858d8cb80
|
|
@ -0,0 +1 @@
|
|||
910d87fbab226671b8e12b236be43970f6b2a3083f30df9586b3f8edf779f4af
|
|
@ -0,0 +1 @@
|
|||
11c65391a6744d7d7c303c6593dafa8e6dca392675974a2a1df2c164afbd4fe1
|
|
@ -0,0 +1 @@
|
|||
cce779cc52b2bb175ccd3d07ac6a7df3711ae362fa0a5004bfc58fa1eb440e1f
|
|
@ -0,0 +1 @@
|
|||
8ec0cc23559ba1b83042bed4abf8c47487ecb999fa66e602fbf4a9edac0569ec
|
|
@ -0,0 +1 @@
|
|||
4f2076138e65849d60cf093f140afa1abaa7beea4d6c95048e6743168a7f17a9
|
|
@ -0,0 +1 @@
|
|||
49a86fa87974f2c0cdc5a38726ab792f70c43e7f215495323d0999fd9f6e45f6
|
|
@ -0,0 +1 @@
|
|||
812f25371d731d03bd4727328ad0daaf954595e24a314dd5f1adccdc3a4532c4
|
|
@ -12632,6 +12632,7 @@ CREATE TABLE ci_builds (
|
|||
scheduling_type smallint,
|
||||
id bigint NOT NULL,
|
||||
stage_id bigint,
|
||||
partition_id bigint DEFAULT 100 NOT NULL,
|
||||
CONSTRAINT check_1e2fbd1b39 CHECK ((lock_version IS NOT NULL))
|
||||
);
|
||||
|
||||
|
@ -12658,7 +12659,8 @@ CREATE TABLE ci_builds_metadata (
|
|||
build_id bigint NOT NULL,
|
||||
id bigint NOT NULL,
|
||||
runtime_runner_features jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL
|
||||
id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
partition_id bigint DEFAULT 100 NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ci_builds_metadata_id_seq
|
||||
|
@ -12823,6 +12825,7 @@ CREATE TABLE ci_job_artifacts (
|
|||
job_id bigint NOT NULL,
|
||||
locked smallint DEFAULT 2,
|
||||
original_filename text,
|
||||
partition_id bigint DEFAULT 100 NOT NULL,
|
||||
CONSTRAINT check_27f0f6dbab CHECK ((file_store IS NOT NULL)),
|
||||
CONSTRAINT check_85573000db CHECK ((char_length(original_filename) <= 512))
|
||||
);
|
||||
|
@ -12928,6 +12931,21 @@ CREATE SEQUENCE ci_namespace_monthly_usages_id_seq
|
|||
|
||||
ALTER SEQUENCE ci_namespace_monthly_usages_id_seq OWNED BY ci_namespace_monthly_usages.id;
|
||||
|
||||
CREATE TABLE ci_partitions (
|
||||
id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ci_partitions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE ci_partitions_id_seq OWNED BY ci_partitions.id;
|
||||
|
||||
CREATE TABLE ci_pending_builds (
|
||||
id bigint NOT NULL,
|
||||
build_id bigint NOT NULL,
|
||||
|
@ -13071,7 +13089,8 @@ CREATE TABLE ci_pipeline_variables (
|
|||
encrypted_value_iv character varying,
|
||||
pipeline_id integer NOT NULL,
|
||||
variable_type smallint DEFAULT 1 NOT NULL,
|
||||
raw boolean DEFAULT true NOT NULL
|
||||
raw boolean DEFAULT true NOT NULL,
|
||||
partition_id bigint DEFAULT 100 NOT NULL
|
||||
);
|
||||
|
||||
CREATE SEQUENCE ci_pipeline_variables_id_seq
|
||||
|
@ -13113,6 +13132,7 @@ CREATE TABLE ci_pipelines (
|
|||
external_pull_request_id bigint,
|
||||
ci_ref_id bigint,
|
||||
locked smallint DEFAULT 1 NOT NULL,
|
||||
partition_id bigint DEFAULT 100 NOT NULL,
|
||||
CONSTRAINT check_d7e99a025e CHECK ((lock_version IS NOT NULL))
|
||||
);
|
||||
|
||||
|
@ -13417,6 +13437,7 @@ CREATE TABLE ci_stages (
|
|||
lock_version integer DEFAULT 0,
|
||||
"position" integer,
|
||||
id bigint NOT NULL,
|
||||
partition_id bigint DEFAULT 100 NOT NULL,
|
||||
CONSTRAINT check_81b431e49b CHECK ((lock_version IS NOT NULL))
|
||||
);
|
||||
|
||||
|
@ -23241,6 +23262,8 @@ ALTER TABLE ONLY ci_namespace_mirrors ALTER COLUMN id SET DEFAULT nextval('ci_na
|
|||
|
||||
ALTER TABLE ONLY ci_namespace_monthly_usages ALTER COLUMN id SET DEFAULT nextval('ci_namespace_monthly_usages_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY ci_partitions ALTER COLUMN id SET DEFAULT nextval('ci_partitions_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY ci_pending_builds ALTER COLUMN id SET DEFAULT nextval('ci_pending_builds_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY ci_pipeline_artifacts ALTER COLUMN id SET DEFAULT nextval('ci_pipeline_artifacts_id_seq'::regclass);
|
||||
|
@ -24976,6 +24999,9 @@ ALTER TABLE ONLY ci_namespace_mirrors
|
|||
ALTER TABLE ONLY ci_namespace_monthly_usages
|
||||
ADD CONSTRAINT ci_namespace_monthly_usages_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY ci_partitions
|
||||
ADD CONSTRAINT ci_partitions_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY ci_pending_builds
|
||||
ADD CONSTRAINT ci_pending_builds_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
|
@ -76,8 +76,7 @@ Example response:
|
|||
},
|
||||
"expires_at": "2012-10-22T14:13:35Z",
|
||||
"access_level": 30,
|
||||
"group_saml_identity": null,
|
||||
"membership_state": "active"
|
||||
"group_saml_identity": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
|
@ -102,8 +101,7 @@ Example response:
|
|||
"extern_uid":"ABC-1234567890",
|
||||
"provider": "group_saml",
|
||||
"saml_provider_id": 10
|
||||
},
|
||||
"membership_state": "active"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -163,8 +161,7 @@ Example response:
|
|||
},
|
||||
"expires_at": "2012-10-22T14:13:35Z",
|
||||
"access_level": 30,
|
||||
"group_saml_identity": null,
|
||||
"membership_state": "active"
|
||||
"group_saml_identity": null
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
|
@ -189,8 +186,7 @@ Example response:
|
|||
"extern_uid":"ABC-1234567890",
|
||||
"provider": "group_saml",
|
||||
"saml_provider_id": 10
|
||||
},
|
||||
"membership_state": "active"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
|
@ -210,8 +206,7 @@ Example response:
|
|||
},
|
||||
"expires_at": "2012-11-22T14:13:35Z",
|
||||
"access_level": 30,
|
||||
"group_saml_identity": null,
|
||||
"membership_state": "active"
|
||||
"group_saml_identity": null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
@ -257,8 +252,7 @@ Example response:
|
|||
"web_url": "http://192.168.1.8:3000/root"
|
||||
},
|
||||
"expires_at": null,
|
||||
"group_saml_identity": null,
|
||||
"membership_state": "active"
|
||||
"group_saml_identity": null
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -305,8 +299,7 @@ Example response:
|
|||
},
|
||||
"email": "john@example.com",
|
||||
"expires_at": null,
|
||||
"group_saml_identity": null,
|
||||
"membership_state": "active"
|
||||
"group_saml_identity": null
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -370,7 +363,6 @@ Example response:
|
|||
"web_url": "http://192.168.1.8:3000/root",
|
||||
"last_activity_on": "2021-01-27",
|
||||
"membership_type": "group_member",
|
||||
"membership_state": "active",
|
||||
"removable": true,
|
||||
"created_at": "2021-01-03T12:16:02.000Z"
|
||||
},
|
||||
|
@ -384,7 +376,6 @@ Example response:
|
|||
"email": "john@example.com",
|
||||
"last_activity_on": "2021-01-25",
|
||||
"membership_type": "group_member",
|
||||
"membership_state": "active",
|
||||
"removable": true,
|
||||
"created_at": "2021-01-04T18:46:42.000Z"
|
||||
},
|
||||
|
@ -397,7 +388,6 @@ Example response:
|
|||
"web_url": "http://192.168.1.8:3000/root",
|
||||
"last_activity_on": "2021-01-20",
|
||||
"membership_type": "group_invite",
|
||||
"membership_state": "awaiting",
|
||||
"removable": false,
|
||||
"created_at": "2021-01-09T07:12:31.000Z"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
type: reference
|
||||
---
|
||||
|
||||
# Mobile DevOps
|
||||
|
||||
GitLab Mobile DevOps is a collection of features and tools designed for mobile developers
|
||||
and teams to automate their build and release process using GitLab CI/CD. Mobile DevOps
|
||||
is an experimental feature developed by [GitLab Incubation Engineering](https://about.gitlab.com/handbook/engineering/incubation/).
|
||||
|
||||
Mobile DevOps is still in development, but you can:
|
||||
|
||||
- [Request a feature](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=feature_request).
|
||||
- [Report a bug](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=report_bug).
|
||||
- [Share feedback](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/feedback/-/issues/new?issuable_template=general_feedback).
|
||||
|
||||
## Code Signing
|
||||
|
||||
[Project-level Secure Files](secure_files/index.md) makes it easier to manage key stores, provision profiles,
|
||||
and signing certificates directly in a GitLab project.
|
||||
|
||||
For a guided walkthrough of this feature, watch the [video demo](https://youtu.be/O7FbJu3H2YM).
|
||||
|
||||
## Review Apps for Mobile
|
||||
|
||||
You can use [Review Apps](review_apps/index.md) to preview changes directly from a merge request.
|
||||
Review Apps for Mobile brings that capability to mobile developers through an integration
|
||||
with [Appetize](https://appetize.io/).
|
||||
|
||||
Watch a [video walkthrough](https://youtu.be/X15mI19TXa4) of this feature, or visit the
|
||||
[setup instructions](https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/readme/-/issues/15)
|
||||
to get started.
|
||||
|
||||
## Mobile SAST
|
||||
|
||||
You can use [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
|
||||
to run static analyzers on code to check for known security vulnerabilities. Mobile SAST
|
||||
expands this functionality for mobile teams with an [experimental SAST feature](../user/application_security/sast/index.md#experimental-features)
|
||||
based on [Mobile Security Framework (MobSF)](https://github.com/MobSF/Mobile-Security-Framework-MobSF).
|
|
@ -272,7 +272,7 @@ Events are handled by counter classes in the `Gitlab::UsageDataCounters` namespa
|
|||
|
||||
1. Listed in [`Gitlab::UsageDataCounters::COUNTERS`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters.rb#L5) to be then included in `Gitlab::UsageData`.
|
||||
|
||||
1. Specified in the metric definition using the `RedisMetric` instrumentation class as a `counter_class` option to be picked up using the [metric instrumentation](metrics_instrumentation.md) framework. Refer to the [Redis metrics](metrics_instrumentation.md#redis-metrics) documentation for an example implementation.
|
||||
1. Specified in the metric definition using the `RedisMetric` instrumentation class by their `prefix` option to be picked up using the [metric instrumentation](metrics_instrumentation.md) framework. Refer to the [Redis metrics](metrics_instrumentation.md#redis-metrics) documentation for an example implementation.
|
||||
|
||||
Inheriting classes are expected to override `KNOWN_EVENTS` and `PREFIX` constants to build event names and associated metrics. For example, for prefix `issues` and events array `%w[create, update, delete]`, three metrics will be added to the Service Ping payload: `counts.issues_create`, `counts.issues_update` and `counts.issues_delete`.
|
||||
|
||||
|
|
|
@ -154,14 +154,16 @@ end
|
|||
|
||||
You can use Redis metrics to track events not kept in the database, for example, a count of how many times the search bar has been used.
|
||||
|
||||
[Example of a merge request that adds a `Redis` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66582).
|
||||
[Example of a merge request that adds a `Redis` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97009).
|
||||
|
||||
Please note that `RedisMetric` class can only be used as the `instrumentation_class` for Redis metrics with simple counters classes (classes that only inherit `BaseCounter` and set `PREFIX` and `KNOWN_EVENTS` constants). In case the counter class has additional logic included in it, a new `instrumentation_class`, inheriting from `RedisMetric`, needs to be created. This new class needs to include the additional logic from the counter class.
|
||||
|
||||
Count unique values for `source_code_pushes` event.
|
||||
|
||||
Required options:
|
||||
|
||||
- `event`: the event name.
|
||||
- `counter_class`: one of the counter classes from the `Gitlab::UsageDataCounters` namespace; it should implement `read` method or inherit it from `BaseCounter`.
|
||||
- `prefix`: the value of the `PREFIX` constant used in the counter classes from the `Gitlab::UsageDataCounters` namespace.
|
||||
|
||||
```yaml
|
||||
time_frame: all
|
||||
|
@ -169,7 +171,7 @@ data_source: redis
|
|||
instrumentation_class: 'RedisMetric'
|
||||
options:
|
||||
event: pushes
|
||||
counter_class: SourceCodeCounter
|
||||
prefix: source_code
|
||||
```
|
||||
|
||||
### Availability-restrained Redis metrics
|
||||
|
@ -200,7 +202,7 @@ data_source: redis
|
|||
instrumentation_class: 'MergeUsageCountRedisMetric'
|
||||
options:
|
||||
event: pushes
|
||||
counter_class: SourceCodeCounter
|
||||
prefix: source_code
|
||||
```
|
||||
|
||||
## Redis HyperLogLog metrics
|
||||
|
|
|
@ -91,6 +91,7 @@ ci_job_artifact_states: :gitlab_ci
|
|||
ci_minutes_additional_packs: :gitlab_ci
|
||||
ci_namespace_monthly_usages: :gitlab_ci
|
||||
ci_namespace_mirrors: :gitlab_ci
|
||||
ci_partitions: :gitlab_ci
|
||||
ci_pending_builds: :gitlab_ci
|
||||
ci_pipeline_artifacts: :gitlab_ci
|
||||
ci_pipeline_chat_data: :gitlab_ci
|
||||
|
|
|
@ -11,37 +11,41 @@ module Gitlab
|
|||
# instrumentation_class: RedisMetric
|
||||
# options:
|
||||
# event: pushes
|
||||
# counter_class: SourceCodeCounter
|
||||
# prefix: source_code
|
||||
#
|
||||
class RedisMetric < BaseMetric
|
||||
include Gitlab::UsageDataCounters::RedisCounter
|
||||
|
||||
def initialize(time_frame:, options: {})
|
||||
super
|
||||
|
||||
raise ArgumentError, "'event' option is required" unless metric_event.present?
|
||||
raise ArgumentError, "'counter class' option is required" unless counter_class.present?
|
||||
raise ArgumentError, "'prefix' option is required" unless prefix.present?
|
||||
end
|
||||
|
||||
def metric_event
|
||||
options[:event]
|
||||
end
|
||||
|
||||
def counter_class_name
|
||||
options[:counter_class]
|
||||
end
|
||||
|
||||
def counter_class
|
||||
"Gitlab::UsageDataCounters::#{counter_class_name}".constantize
|
||||
def prefix
|
||||
options[:prefix]
|
||||
end
|
||||
|
||||
def value
|
||||
redis_usage_data do
|
||||
counter_class.read(metric_event)
|
||||
total_count(redis_key)
|
||||
end
|
||||
end
|
||||
|
||||
def suggested_name
|
||||
Gitlab::Usage::Metrics::NameSuggestion.for(:redis)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redis_key
|
||||
"USAGE_#{prefix}_#{metric_event}".upcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17962,6 +17962,9 @@ msgstr ""
|
|||
msgid "Global Shortcuts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Global notification level"
|
||||
msgstr ""
|
||||
|
||||
msgid "Global notification settings"
|
||||
msgstr ""
|
||||
|
||||
|
@ -18049,6 +18052,12 @@ msgstr ""
|
|||
msgid "GlobalSearch|project"
|
||||
msgstr ""
|
||||
|
||||
msgid "GlobalShortcuts|Copied source branch name to clipboard."
|
||||
msgstr ""
|
||||
|
||||
msgid "GlobalShortcuts|Unable to copy the source branch name at this time."
|
||||
msgstr ""
|
||||
|
||||
msgid "Globally-allowed IP ranges"
|
||||
msgstr ""
|
||||
|
||||
|
@ -26698,6 +26707,9 @@ msgstr ""
|
|||
msgid "Nothing to preview."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notification Email"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notification events"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"@gitlab/at.js": "1.5.7",
|
||||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/svgs": "3.3.0",
|
||||
"@gitlab/ui": "43.9.3",
|
||||
"@gitlab/ui": "43.13.0",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20220815034418",
|
||||
"@rails/actioncable": "6.1.4-7",
|
||||
|
@ -197,7 +197,7 @@
|
|||
"yaml": "^2.0.0-10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gitlab/eslint-plugin": "16.0.0",
|
||||
"@gitlab/eslint-plugin": "17.0.0",
|
||||
"@gitlab/stylelint-config": "4.1.0",
|
||||
"@graphql-eslint/eslint-plugin": "3.10.7",
|
||||
"@testing-library/dom": "^7.16.2",
|
||||
|
|
|
@ -31,9 +31,14 @@ RSpec.describe 'Database schema' do
|
|||
boards: %w[milestone_id iteration_id],
|
||||
chat_names: %w[chat_id team_id user_id],
|
||||
chat_teams: %w[team_id],
|
||||
ci_builds: %w[erased_by_id trigger_request_id],
|
||||
ci_builds: %w[erased_by_id trigger_request_id partition_id],
|
||||
ci_builds_metadata: %w[partition_id],
|
||||
ci_job_artifacts: %w[partition_id],
|
||||
ci_namespace_monthly_usages: %w[namespace_id],
|
||||
ci_pipeline_variables: %w[partition_id],
|
||||
ci_pipelines: %w[partition_id],
|
||||
ci_runner_projects: %w[runner_id],
|
||||
ci_stages: %w[partition_id],
|
||||
ci_trigger_requests: %w[commit_id],
|
||||
cluster_providers_aws: %w[security_group_id vpc_id access_key_id],
|
||||
cluster_providers_gcp: %w[gcp_project_id operation_id],
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
|
||||
import { mockList, mockIssue2, mockIssue, mockIssue3, mockIssue4 } from 'jest/boards/mock_data';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
|
@ -19,6 +19,7 @@ describe('Board Card Move to position', () => {
|
|||
let trackingSpy;
|
||||
let store;
|
||||
let dispatch;
|
||||
const itemIndex = 1;
|
||||
|
||||
const createStoreOptions = () => {
|
||||
const state = {
|
||||
|
@ -42,7 +43,7 @@ describe('Board Card Move to position', () => {
|
|||
};
|
||||
|
||||
const createComponent = (propsData) => {
|
||||
wrapper = shallowMountExtended(BoardCardMoveToPosition, {
|
||||
wrapper = shallowMount(BoardCardMoveToPosition, {
|
||||
store,
|
||||
propsData: {
|
||||
item: mockIssue2,
|
||||
|
@ -66,7 +67,6 @@ describe('Board Card Move to position', () => {
|
|||
wrapper.destroy();
|
||||
});
|
||||
|
||||
const findEllipsesButton = () => wrapper.findByTestId('move-card-dropdown');
|
||||
const findMoveToPositionDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findDropdownItems = () => findMoveToPositionDropdown().findAllComponents(GlDropdownItem);
|
||||
const findDropdownItemAtIndex = (index) => findDropdownItems().at(index);
|
||||
|
@ -74,7 +74,7 @@ describe('Board Card Move to position', () => {
|
|||
describe('Dropdown', () => {
|
||||
describe('Dropdown button', () => {
|
||||
it('has an icon with vertical ellipsis', () => {
|
||||
expect(findEllipsesButton().exists()).toBe(true);
|
||||
expect(findMoveToPositionDropdown().exists()).toBe(true);
|
||||
expect(findMoveToPositionDropdown().props('icon')).toBe('ellipsis_v');
|
||||
});
|
||||
|
||||
|
@ -82,24 +82,11 @@ describe('Board Card Move to position', () => {
|
|||
findMoveToPositionDropdown().vm.$emit('click');
|
||||
expect(findDropdownItems()).toHaveLength(dropdownOptions.length);
|
||||
});
|
||||
|
||||
it('is opened on the click of vertical ellipsis and has 1 dropdown items when number of list items > 10', () => {
|
||||
wrapper.destroy();
|
||||
|
||||
createComponent({
|
||||
list: {
|
||||
...mockList,
|
||||
id: 'gid://gitlab/List/2',
|
||||
},
|
||||
});
|
||||
findMoveToPositionDropdown().vm.$emit('click');
|
||||
expect(findDropdownItems()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dropdown options', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ index: 1 });
|
||||
createComponent({ index: itemIndex });
|
||||
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
|
||||
dispatch = jest.spyOn(store, 'dispatch').mockImplementation(() => {});
|
||||
});
|
||||
|
@ -109,13 +96,13 @@ describe('Board Card Move to position', () => {
|
|||
});
|
||||
|
||||
it.each`
|
||||
dropdownIndex | dropdownLabel | trackLabel | moveAfterId | moveBeforeId
|
||||
${0} | ${BoardCardMoveToPosition.i18n.moveToStartText} | ${'move_to_start'} | ${mockIssue.id} | ${undefined}
|
||||
${1} | ${BoardCardMoveToPosition.i18n.moveToEndText} | ${'move_to_end'} | ${undefined} | ${mockIssue4.id}
|
||||
dropdownIndex | dropdownLabel | trackLabel | positionInList
|
||||
${0} | ${BoardCardMoveToPosition.i18n.moveToStartText} | ${'move_to_start'} | ${0}
|
||||
${1} | ${BoardCardMoveToPosition.i18n.moveToEndText} | ${'move_to_end'} | ${-1}
|
||||
`(
|
||||
'on click of dropdown index $dropdownIndex with label $dropdownLabel should call moveItem action with tracking label $trackLabel',
|
||||
async ({ dropdownIndex, dropdownLabel, trackLabel, moveAfterId, moveBeforeId }) => {
|
||||
await findEllipsesButton().vm.$emit('click');
|
||||
async ({ dropdownIndex, dropdownLabel, trackLabel, positionInList }) => {
|
||||
await findMoveToPositionDropdown().vm.$emit('click');
|
||||
|
||||
expect(findDropdownItemAtIndex(dropdownIndex).text()).toBe(dropdownLabel);
|
||||
await findDropdownItemAtIndex(dropdownIndex).vm.$emit('click', {
|
||||
|
@ -134,9 +121,10 @@ describe('Board Card Move to position', () => {
|
|||
itemId: mockIssue2.id,
|
||||
itemIid: mockIssue2.iid,
|
||||
itemPath: mockIssue2.referencePath,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
positionInList,
|
||||
toListId: mockList.id,
|
||||
allItemsLoadedInList: true,
|
||||
atIndex: itemIndex,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1056,6 +1056,8 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
|
|||
originalIndex = 0,
|
||||
moveBeforeId = undefined,
|
||||
moveAfterId = undefined,
|
||||
allItemsLoadedInList = true,
|
||||
listPosition = undefined,
|
||||
} = {}) => {
|
||||
state = {
|
||||
boardLists: {
|
||||
|
@ -1065,12 +1067,28 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
|
|||
boardItems: { [itemId]: originalIssue },
|
||||
boardItemsByListId: { [fromListId]: [123] },
|
||||
};
|
||||
params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
|
||||
params = {
|
||||
itemId,
|
||||
fromListId,
|
||||
toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
listPosition,
|
||||
allItemsLoadedInList,
|
||||
};
|
||||
moveMutations = [
|
||||
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
|
||||
{
|
||||
type: types.ADD_BOARD_ITEM_TO_LIST,
|
||||
payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
|
||||
payload: {
|
||||
itemId,
|
||||
listId: toListId,
|
||||
moveBeforeId,
|
||||
moveAfterId,
|
||||
listPosition,
|
||||
allItemsLoadedInList,
|
||||
atIndex: originalIndex,
|
||||
},
|
||||
},
|
||||
];
|
||||
undoMutations = [
|
||||
|
@ -1365,10 +1383,18 @@ describe('updateIssueOrder', () => {
|
|||
{ moveData },
|
||||
state,
|
||||
[
|
||||
{
|
||||
type: types.MUTATE_ISSUE_IN_PROGRESS,
|
||||
payload: true,
|
||||
},
|
||||
{
|
||||
type: types.MUTATE_ISSUE_SUCCESS,
|
||||
payload: { issue: rawIssue },
|
||||
},
|
||||
{
|
||||
type: types.MUTATE_ISSUE_IN_PROGRESS,
|
||||
payload: false,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
@ -1389,6 +1415,14 @@ describe('updateIssueOrder', () => {
|
|||
{ moveData },
|
||||
state,
|
||||
[
|
||||
{
|
||||
type: types.MUTATE_ISSUE_IN_PROGRESS,
|
||||
payload: true,
|
||||
},
|
||||
{
|
||||
type: types.MUTATE_ISSUE_IN_PROGRESS,
|
||||
payload: false,
|
||||
},
|
||||
{
|
||||
type: types.SET_ERROR,
|
||||
payload: 'An error occurred while moving the issue. Please try again.',
|
||||
|
|
|
@ -513,6 +513,31 @@ describe('Board Store Mutations', () => {
|
|||
listState: [mockIssue2.id, mockIssue.id],
|
||||
},
|
||||
],
|
||||
[
|
||||
'to the top of the list',
|
||||
{
|
||||
payload: {
|
||||
itemId: mockIssue2.id,
|
||||
listId: mockList.id,
|
||||
positionInList: 0,
|
||||
atIndex: 1,
|
||||
},
|
||||
listState: [mockIssue2.id, mockIssue.id],
|
||||
},
|
||||
],
|
||||
[
|
||||
'to the bottom of the list when the list is fully loaded',
|
||||
{
|
||||
payload: {
|
||||
itemId: mockIssue2.id,
|
||||
listId: mockList.id,
|
||||
positionInList: -1,
|
||||
atIndex: 0,
|
||||
allItemsLoadedInList: true,
|
||||
},
|
||||
listState: [mockIssue.id, mockIssue2.id],
|
||||
},
|
||||
],
|
||||
])(`inserts an item into a list %s`, (_, { payload, listState }) => {
|
||||
mutations.ADD_BOARD_ITEM_TO_LIST(state, payload);
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ describe('IDE commit module actions', () => {
|
|||
branch,
|
||||
});
|
||||
store.state.openFiles.forEach((entry) => {
|
||||
expect(entry.changed).toBeFalsy();
|
||||
expect(entry.changed).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,18 +11,18 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::RedisMetric, :clean_git
|
|||
|
||||
let(:expected_value) { 4 }
|
||||
|
||||
it_behaves_like 'a correct instrumented metric value', { options: { event: 'pushes', counter_class: 'SourceCodeCounter' } }
|
||||
it_behaves_like 'a correct instrumented metric value', { options: { event: 'pushes', prefix: 'source_code' } }
|
||||
|
||||
it 'raises an exception if event option is not present' do
|
||||
expect { described_class.new(counter_class: 'SourceCodeCounter') }.to raise_error(ArgumentError)
|
||||
expect { described_class.new(prefix: 'source_code') }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
it 'raises an exception if counter_class option is not present' do
|
||||
it 'raises an exception if prefix option is not present' do
|
||||
expect { described_class.new(event: 'pushes') }.to raise_error(ArgumentError)
|
||||
end
|
||||
|
||||
describe 'children classes' do
|
||||
let(:options) { { event: 'pushes', counter_class: 'SourceCodeCounter' } }
|
||||
let(:options) { { event: 'pushes', prefix: 'source_code' } }
|
||||
|
||||
context 'availability not defined' do
|
||||
subject { Class.new(described_class).new(time_frame: nil, options: options) }
|
||||
|
|
16
yarn.lock
16
yarn.lock
|
@ -1027,10 +1027,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
|
||||
integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg==
|
||||
|
||||
"@gitlab/eslint-plugin@16.0.0":
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-16.0.0.tgz#83b71bb3f749c6e52138d2c1c17ac623e7b2e3db"
|
||||
integrity sha512-2n7geoRPkeMAq4GCqyvFzcTgcSrTM7pdCOxfcqIeuTmh/PFGhh+m7YC+YC4enhGOCN8lo08buLZhXkSgWiHSqA==
|
||||
"@gitlab/eslint-plugin@17.0.0":
|
||||
version "17.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-17.0.0.tgz#5451fbbad96b09d812af2afb247f6602fe0be6c6"
|
||||
integrity sha512-c+sJtjzYl+KGPtZScU8Mji9seJw7dSEn31APyYEYTyWp72yMsFvXmg46txT2QCz+ueZlqk0/C2IQmgfe6fLcBw==
|
||||
dependencies:
|
||||
"@babel/core" "^7.17.0"
|
||||
"@babel/eslint-parser" "^7.17.0"
|
||||
|
@ -1064,10 +1064,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.3.0.tgz#99b044484fcf3d5a6431281e320e2405540ff5a9"
|
||||
integrity sha512-S8Hqf+ms8aNrSgmci9SVoIyj/0qQnizU5uV5vUPAOwiufMDFDyI5qfcgn4EYZ6mnju3LiO+ReSL/PPTD4qNgHA==
|
||||
|
||||
"@gitlab/ui@43.9.3":
|
||||
version "43.9.3"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-43.9.3.tgz#2dd91b14da769a873e45ffe07b5863f6c47211ba"
|
||||
integrity sha512-TONSf+6UJYWTVs5qnItR1uLZ/0kBE8jGN8aLOVv4CDAsORvln0ZxtcZvMTCFp76YEtzXLkMUfvm7ZngQ26tIiA==
|
||||
"@gitlab/ui@43.13.0":
|
||||
version "43.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-43.13.0.tgz#7e4e7d41287cfba8a46dbdd3c8ba998a853a9ad2"
|
||||
integrity sha512-y0BrVKsqRBEQMrsJseakBeMrFHVMTg7DVMa3tbdkKkrruV8SYOsX8wLrv20taDhiMlceKRB8lF5gLTPPHLwCGA==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.11.2"
|
||||
bootstrap-vue "2.20.1"
|
||||
|
|
Loading…
Reference in New Issue