Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
02c0ca3a07
commit
ca3ebabdfc
|
|
@ -745,7 +745,6 @@ Layout/LineLength:
|
|||
- 'ee/app/workers/geo/destroy_worker.rb'
|
||||
- 'ee/app/workers/geo/scheduler/scheduler_worker.rb'
|
||||
- 'ee/app/workers/geo/secondary/registry_consistency_worker.rb'
|
||||
- 'ee/app/workers/geo/verification_worker.rb'
|
||||
- 'ee/app/workers/repository_update_mirror_worker.rb'
|
||||
- 'ee/app/workers/security/orchestration_policy_rule_schedule_namespace_worker.rb'
|
||||
- 'ee/app/workers/security/orchestration_policy_rule_schedule_worker.rb'
|
||||
|
|
@ -1833,7 +1832,6 @@ Layout/LineLength:
|
|||
- 'ee/spec/workers/geo/secondary/registry_consistency_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_batch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_timeout_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_worker_spec.rb'
|
||||
- 'ee/spec/workers/import_software_licenses_worker_spec.rb'
|
||||
- 'ee/spec/workers/incident_management/oncall_rotations/persist_all_rotations_shifts_job_spec.rb'
|
||||
- 'ee/spec/workers/incident_management/oncall_rotations/persist_shifts_job_spec.rb'
|
||||
|
|
|
|||
|
|
@ -173,7 +173,6 @@ RSpec/VerifiedDoubles:
|
|||
- 'ee/spec/workers/geo/verification_batch_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_cron_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_timeout_worker_spec.rb'
|
||||
- 'ee/spec/workers/geo/verification_worker_spec.rb'
|
||||
- 'ee/spec/workers/iterations/cadences/create_iterations_worker_spec.rb'
|
||||
- 'ee/spec/workers/iterations/roll_over_issues_worker_spec.rb'
|
||||
- 'ee/spec/workers/ldap_group_sync_worker_spec.rb'
|
||||
|
|
|
|||
|
|
@ -292,7 +292,6 @@ SidekiqLoadBalancing/WorkerDataConsistency:
|
|||
- 'ee/app/workers/geo/verification_cron_worker.rb'
|
||||
- 'ee/app/workers/geo/verification_state_backfill_worker.rb'
|
||||
- 'ee/app/workers/geo/verification_timeout_worker.rb'
|
||||
- 'ee/app/workers/geo/verification_worker.rb'
|
||||
- 'ee/app/workers/gitlab_subscriptions/schedule_refresh_seats_worker.rb'
|
||||
- 'ee/app/workers/gitlab_subscriptions/trials/apply_trial_worker.rb'
|
||||
- 'ee/app/workers/group_saml_group_sync_worker.rb'
|
||||
|
|
|
|||
|
|
@ -11,11 +11,7 @@ import { isUserBusy } from '~/set_status_modal/utils';
|
|||
import SidebarMediator from '~/sidebar/sidebar_mediator';
|
||||
import { currentAssignees, linkedItems } from '~/graphql_shared/issuable_client';
|
||||
import { state } from '~/sidebar/components/reviewers/sidebar_reviewers.vue';
|
||||
import {
|
||||
ISSUABLE_EPIC,
|
||||
WORK_ITEMS_TYPE_MAP,
|
||||
WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
} from '~/work_items/constants';
|
||||
import { ISSUABLE_EPIC, NAME_TO_ICON_MAP, WORK_ITEM_TYPE_NAME_EPIC } from '~/work_items/constants';
|
||||
import AjaxCache from './lib/utils/ajax_cache';
|
||||
import { spriteIcon } from './lib/utils/common_utils';
|
||||
import { newDate } from './lib/utils/datetime_utility';
|
||||
|
|
@ -1259,7 +1255,7 @@ GfmAutoComplete.Issues = {
|
|||
},
|
||||
templateFunction({ id, title, reference, iconName }) {
|
||||
const mappedIconName =
|
||||
iconName === ISSUABLE_EPIC ? WORK_ITEMS_TYPE_MAP[WORK_ITEM_TYPE_ENUM_EPIC].icon : iconName;
|
||||
iconName === ISSUABLE_EPIC ? NAME_TO_ICON_MAP[WORK_ITEM_TYPE_NAME_EPIC] : iconName;
|
||||
const icon = mappedIconName
|
||||
? spriteIcon(mappedIconName, 'gl-fill-icon-subtle s16 gl-mr-2')
|
||||
: '';
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
WIDGET_TYPE_HIERARCHY,
|
||||
WIDGET_TYPE_LINKED_ITEMS,
|
||||
WIDGET_TYPE_ASSIGNEES,
|
||||
WIDGET_TYPE_VULNERABILITIES,
|
||||
} from '~/work_items/constants';
|
||||
|
||||
import isExpandedHierarchyTreeChildQuery from '~/work_items/graphql/client/is_expanded_hierarchy_tree_child.query.graphql';
|
||||
|
|
@ -133,6 +134,15 @@ export const config = {
|
|||
},
|
||||
},
|
||||
},
|
||||
WorkItemWidgetVulnerabilities: {
|
||||
fields: {
|
||||
// If we add any key args, the relatedVulnerabilities field becomes relatedVulnerabilities({"first":50,"after":"xyz"}) and
|
||||
// kills any possibility to handle it on the widget level without hardcoding a string.
|
||||
relatedVulnerabilities: {
|
||||
keyArgs: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
WorkItem: {
|
||||
fields: {
|
||||
// Prevent `reference` from being transformed into `reference({"fullPath":true})`
|
||||
|
|
@ -196,6 +206,25 @@ export const config = {
|
|||
};
|
||||
}
|
||||
|
||||
// we want to concat next page of vulnerabilities work items within Vulnerabilities widget to the existing ones
|
||||
if (
|
||||
incomingWidget?.type === WIDGET_TYPE_VULNERABILITIES &&
|
||||
context.variables.after &&
|
||||
incomingWidget.relatedVulnerabilities?.nodes
|
||||
) {
|
||||
// concatPagination won't work because we were placing new widget here so we have to do this manually
|
||||
return {
|
||||
...incomingWidget,
|
||||
relatedVulnerabilities: {
|
||||
...incomingWidget.relatedVulnerabilities,
|
||||
nodes: [
|
||||
...existingWidget.relatedVulnerabilities.nodes,
|
||||
...incomingWidget.relatedVulnerabilities.nodes,
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// this ensures that we don’t override linkedItems.workItem when updating parent
|
||||
if (incomingWidget?.type === WIDGET_TYPE_LINKED_ITEMS) {
|
||||
if (!incomingWidget.linkedItems) {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export default {
|
|||
return newWorkItemPath({
|
||||
fullPath: this.fullPath,
|
||||
isGroup: this.isGroup,
|
||||
workItemTypeName: NAME_TO_ENUM_MAP[this.selectedWorkItemTypeName],
|
||||
workItemType: this.selectedWorkItemTypeName,
|
||||
query: this.newWorkItemPathQuery,
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -53,9 +53,6 @@ export default {
|
|||
workItemType() {
|
||||
return this.workItem?.workItemType?.name;
|
||||
},
|
||||
workItemIconName() {
|
||||
return this.workItem?.workItemType?.iconName;
|
||||
},
|
||||
workItemMovedToWorkItemUrl() {
|
||||
return this.workItem?.movedToWorkItemUrl;
|
||||
},
|
||||
|
|
@ -120,7 +117,6 @@ export default {
|
|||
<locked-badge v-if="isDiscussionLocked" class="gl-align-middle" :issuable-type="workItemType" />
|
||||
<work-item-type-icon
|
||||
class="gl-align-middle"
|
||||
:work-item-icon-name="workItemIconName"
|
||||
:work-item-type="workItemType"
|
||||
show-text
|
||||
icon-class="gl-fill-icon-subtle"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export default {
|
|||
v-for="rolledUpCount in filteredRollUpCountsByType"
|
||||
:key="rolledUpCount.workItemType.name"
|
||||
>
|
||||
<work-item-type-icon :work-item-icon-name="rolledUpCount.workItemType.iconName" />
|
||||
<work-item-type-icon :work-item-type="rolledUpCount.workItemType.name" />
|
||||
{{ rolledUpCount.countsByState.all }}
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default {
|
|||
:key="rolledUpCount.workItemType.name"
|
||||
data-testid="rolled-up-type-info"
|
||||
>
|
||||
<work-item-type-icon :work-item-icon-name="rolledUpCount.workItemType.iconName" />
|
||||
<work-item-type-icon :work-item-type="rolledUpCount.workItemType.name" />
|
||||
<span class="gl-font-bold"
|
||||
>{{ rolledUpCount.countsByState.closed }}/{{ rolledUpCount.countsByState.all }}</span
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { WORK_ITEMS_TYPE_MAP } from '../constants';
|
||||
import { NAME_TO_ICON_MAP, NAME_TO_TEXT_MAP } from '../constants';
|
||||
import { convertTypeEnumToName } from '../utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -12,19 +13,13 @@ export default {
|
|||
props: {
|
||||
workItemType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
showText: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
workItemIconName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
showTooltipOnHover: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
|
|
@ -42,26 +37,22 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
workItemTypeUppercase() {
|
||||
return this.workItemType.toUpperCase().split(' ').join('_');
|
||||
},
|
||||
iconName() {
|
||||
// TODO Delete this conditional once we have an `issue-type-epic` icon
|
||||
if (this.workItemIconName === 'issue-type-epic') {
|
||||
return 'epic';
|
||||
}
|
||||
|
||||
return (
|
||||
this.workItemIconName ||
|
||||
WORK_ITEMS_TYPE_MAP[this.workItemTypeUppercase]?.icon ||
|
||||
'issue-type-issue'
|
||||
);
|
||||
workItemTypeEnum() {
|
||||
// Since this component is used by work items and legacy issues, workItemType can be
|
||||
// a legacy issue type or work item name, so normalize it into a work item enum
|
||||
return this.workItemType.replaceAll(' ', '_').toUpperCase();
|
||||
},
|
||||
workItemTypeName() {
|
||||
return WORK_ITEMS_TYPE_MAP[this.workItemTypeUppercase]?.name;
|
||||
return convertTypeEnumToName(this.workItemTypeEnum);
|
||||
},
|
||||
iconName() {
|
||||
return NAME_TO_ICON_MAP[this.workItemTypeName] || 'issue-type-issue';
|
||||
},
|
||||
workItemTypeText() {
|
||||
return NAME_TO_TEXT_MAP[this.workItemTypeName];
|
||||
},
|
||||
workItemTooltipTitle() {
|
||||
return this.showTooltipOnHover ? this.workItemTypeName : '';
|
||||
return this.showTooltipOnHover ? this.workItemTypeText : '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -76,6 +67,6 @@ export default {
|
|||
:variant="iconVariant"
|
||||
:class="iconClass"
|
||||
/>
|
||||
<span v-if="workItemTypeName" :class="{ 'gl-sr-only': !showText }">{{ workItemTypeName }}</span>
|
||||
<span v-if="workItemTypeText" :class="{ 'gl-sr-only': !showText }">{{ workItemTypeText }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -90,63 +90,6 @@ export const sprintfWorkItem = (msg, workItemTypeArg, parentWorkItemType = '') =
|
|||
);
|
||||
};
|
||||
|
||||
export const WORK_ITEMS_TYPE_MAP = {
|
||||
[WORK_ITEM_TYPE_ENUM_INCIDENT]: {
|
||||
icon: `issue-type-incident`,
|
||||
name: s__('WorkItem|Incident'),
|
||||
value: WORK_ITEM_TYPE_NAME_INCIDENT,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_ISSUE]: {
|
||||
icon: `issue-type-issue`,
|
||||
name: s__('WorkItem|Issue'),
|
||||
value: WORK_ITEM_TYPE_NAME_ISSUE,
|
||||
routeParamName: 'issues',
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_TASK]: {
|
||||
icon: `issue-type-task`,
|
||||
name: s__('WorkItem|Task'),
|
||||
value: WORK_ITEM_TYPE_NAME_TASK,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_TEST_CASE]: {
|
||||
icon: `issue-type-test-case`,
|
||||
name: s__('WorkItem|Test case'),
|
||||
value: WORK_ITEM_TYPE_NAME_TEST_CASE,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_REQUIREMENTS]: {
|
||||
icon: `issue-type-requirements`,
|
||||
name: s__('WorkItem|Requirements'),
|
||||
value: WORK_ITEM_TYPE_NAME_REQUIREMENTS,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_OBJECTIVE]: {
|
||||
icon: `issue-type-objective`,
|
||||
name: s__('WorkItem|Objective'),
|
||||
value: WORK_ITEM_TYPE_NAME_OBJECTIVE,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_KEY_RESULT]: {
|
||||
icon: `issue-type-keyresult`,
|
||||
name: s__('WorkItem|Key result'),
|
||||
value: WORK_ITEM_TYPE_NAME_KEY_RESULT,
|
||||
},
|
||||
[WORK_ITEM_TYPE_ENUM_EPIC]: {
|
||||
icon: `epic`,
|
||||
name: s__('WorkItem|Epic'),
|
||||
value: WORK_ITEM_TYPE_NAME_EPIC,
|
||||
routeParamName: 'epics',
|
||||
},
|
||||
};
|
||||
|
||||
export const NAME_TO_ENUM_MAP = {
|
||||
[WORK_ITEM_TYPE_NAME_EPIC]: WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
[WORK_ITEM_TYPE_NAME_INCIDENT]: WORK_ITEM_TYPE_ENUM_INCIDENT,
|
||||
[WORK_ITEM_TYPE_NAME_ISSUE]: WORK_ITEM_TYPE_ENUM_ISSUE,
|
||||
[WORK_ITEM_TYPE_NAME_KEY_RESULT]: WORK_ITEM_TYPE_ENUM_KEY_RESULT,
|
||||
[WORK_ITEM_TYPE_NAME_OBJECTIVE]: WORK_ITEM_TYPE_ENUM_OBJECTIVE,
|
||||
[WORK_ITEM_TYPE_NAME_REQUIREMENTS]: WORK_ITEM_TYPE_ENUM_REQUIREMENTS,
|
||||
[WORK_ITEM_TYPE_NAME_TASK]: WORK_ITEM_TYPE_ENUM_TASK,
|
||||
[WORK_ITEM_TYPE_NAME_TEST_CASE]: WORK_ITEM_TYPE_ENUM_TEST_CASE,
|
||||
[WORK_ITEM_TYPE_NAME_TICKET]: WORK_ITEM_TYPE_ENUM_TICKET,
|
||||
};
|
||||
|
||||
export const FORM_TYPES = {
|
||||
create: 'create',
|
||||
add: 'add',
|
||||
|
|
@ -329,6 +272,35 @@ export const ALLOWED_CONVERSION_TYPES = [
|
|||
WORK_ITEM_TYPE_NAME_ISSUE,
|
||||
];
|
||||
|
||||
export const NAME_TO_ENUM_MAP = {
|
||||
[WORK_ITEM_TYPE_NAME_EPIC]: WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
[WORK_ITEM_TYPE_NAME_INCIDENT]: WORK_ITEM_TYPE_ENUM_INCIDENT,
|
||||
[WORK_ITEM_TYPE_NAME_ISSUE]: WORK_ITEM_TYPE_ENUM_ISSUE,
|
||||
[WORK_ITEM_TYPE_NAME_KEY_RESULT]: WORK_ITEM_TYPE_ENUM_KEY_RESULT,
|
||||
[WORK_ITEM_TYPE_NAME_OBJECTIVE]: WORK_ITEM_TYPE_ENUM_OBJECTIVE,
|
||||
[WORK_ITEM_TYPE_NAME_REQUIREMENTS]: WORK_ITEM_TYPE_ENUM_REQUIREMENTS,
|
||||
[WORK_ITEM_TYPE_NAME_TASK]: WORK_ITEM_TYPE_ENUM_TASK,
|
||||
[WORK_ITEM_TYPE_NAME_TEST_CASE]: WORK_ITEM_TYPE_ENUM_TEST_CASE,
|
||||
[WORK_ITEM_TYPE_NAME_TICKET]: WORK_ITEM_TYPE_ENUM_TICKET,
|
||||
};
|
||||
|
||||
export const NAME_TO_ICON_MAP = {
|
||||
[WORK_ITEM_TYPE_NAME_EPIC]: 'epic',
|
||||
[WORK_ITEM_TYPE_NAME_INCIDENT]: 'issue-type-incident',
|
||||
[WORK_ITEM_TYPE_NAME_ISSUE]: 'issue-type-issue',
|
||||
[WORK_ITEM_TYPE_NAME_KEY_RESULT]: 'issue-type-keyresult',
|
||||
[WORK_ITEM_TYPE_NAME_OBJECTIVE]: 'issue-type-objective',
|
||||
[WORK_ITEM_TYPE_NAME_REQUIREMENTS]: 'issue-type-requirements',
|
||||
[WORK_ITEM_TYPE_NAME_TASK]: 'issue-type-task',
|
||||
[WORK_ITEM_TYPE_NAME_TEST_CASE]: 'issue-type-test-case',
|
||||
[WORK_ITEM_TYPE_NAME_TICKET]: 'issue-type-ticket',
|
||||
};
|
||||
|
||||
export const NAME_TO_ROUTE_MAP = {
|
||||
[WORK_ITEM_TYPE_NAME_EPIC]: WORK_ITEM_TYPE_ROUTE_EPIC,
|
||||
[WORK_ITEM_TYPE_NAME_ISSUE]: WORK_ITEM_TYPE_ROUTE_ISSUE,
|
||||
};
|
||||
|
||||
export const NAME_TO_TEXT_MAP = {
|
||||
[WORK_ITEM_TYPE_NAME_EPIC]: s__('WorkItem|Epic'),
|
||||
[WORK_ITEM_TYPE_NAME_INCIDENT]: s__('WorkItem|Incident'),
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import { parseBoolean } from '~/lib/utils/common_utils';
|
|||
import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants';
|
||||
import {
|
||||
DEFAULT_PAGE_SIZE_CHILD_ITEMS,
|
||||
ISSUABLE_EPIC,
|
||||
NAME_TO_ENUM_MAP,
|
||||
NAME_TO_ICON_MAP,
|
||||
NAME_TO_ROUTE_MAP,
|
||||
NEW_WORK_ITEM_GID,
|
||||
NEW_WORK_ITEM_IID,
|
||||
STATE_CLOSED,
|
||||
|
|
@ -34,9 +35,7 @@ import {
|
|||
WIDGET_TYPE_TIME_TRACKING,
|
||||
WIDGET_TYPE_VULNERABILITIES,
|
||||
WIDGET_TYPE_WEIGHT,
|
||||
WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
WORK_ITEM_TYPE_ROUTE_WORK_ITEM,
|
||||
WORK_ITEMS_TYPE_MAP,
|
||||
} from './constants';
|
||||
|
||||
export const isAssigneesWidget = (widget) => widget.type === WIDGET_TYPE_ASSIGNEES;
|
||||
|
|
@ -129,11 +128,6 @@ export const formatLabelForListbox = (label) => ({
|
|||
export const convertTypeEnumToName = (workItemTypeEnum) =>
|
||||
Object.keys(NAME_TO_ENUM_MAP).find((name) => NAME_TO_ENUM_MAP[name] === workItemTypeEnum);
|
||||
|
||||
export const getWorkItemIcon = (icon) => {
|
||||
if (icon === ISSUABLE_EPIC) return WORK_ITEMS_TYPE_MAP[WORK_ITEM_TYPE_ENUM_EPIC].icon;
|
||||
return icon;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Remove this method with https://gitlab.com/gitlab-org/gitlab/-/issues/479637
|
||||
* We're currently setting children count per page based on `DEFAULT_PAGE_SIZE_CHILD_ITEMS`
|
||||
|
|
@ -149,7 +143,7 @@ export const getDefaultHierarchyChildrenCount = () => {
|
|||
export const formatAncestors = (workItem) =>
|
||||
findHierarchyWidgetAncestors(workItem).map((ancestor) => ({
|
||||
...ancestor,
|
||||
icon: getWorkItemIcon(ancestor.workItemType?.iconName),
|
||||
icon: NAME_TO_ICON_MAP[ancestor.workItemType?.name],
|
||||
href: ancestor.webUrl,
|
||||
}));
|
||||
|
||||
|
|
@ -279,11 +273,10 @@ export const markdownPreviewPath = ({ fullPath, iid, isGroup = false }) => {
|
|||
};
|
||||
|
||||
// the path for creating a new work item of that type, e.g. /groups/gitlab-org/-/epics/new
|
||||
export const newWorkItemPath = ({ fullPath, isGroup = false, workItemTypeName, query = '' }) => {
|
||||
export const newWorkItemPath = ({ fullPath, isGroup = false, workItemType, query = '' }) => {
|
||||
const domain = gon.relative_url_root || '';
|
||||
const basePath = isGroup ? `groups/${fullPath}` : fullPath;
|
||||
const type =
|
||||
WORK_ITEMS_TYPE_MAP[workItemTypeName]?.routeParamName || WORK_ITEM_TYPE_ROUTE_WORK_ITEM;
|
||||
const type = NAME_TO_ROUTE_MAP[workItemType] || WORK_ITEM_TYPE_ROUTE_WORK_ITEM;
|
||||
return `${domain}/${basePath}/-/${type}/new${query}`;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module NumbersHelper
|
||||
WORDS = %w[zero one two three four five six seven eight nine].freeze
|
||||
|
||||
def limited_counter_with_delimiter(resource, **options)
|
||||
limit = options.fetch(:limit, 1000).to_i
|
||||
count = resource.page.total_count_with_limit(:all, limit: limit)
|
||||
|
|
@ -13,4 +15,10 @@ module NumbersHelper
|
|||
number_with_delimiter(count, options)
|
||||
end
|
||||
end
|
||||
|
||||
def number_in_words(num)
|
||||
raise ArgumentError, _('Input must be an integer between 0 and 9') unless num.between?(0, 9)
|
||||
|
||||
WORDS[num]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -79,8 +79,12 @@ module Namespaces
|
|||
end
|
||||
end
|
||||
|
||||
def traversal_path
|
||||
"#{traversal_ids.join('/')}/"
|
||||
def traversal_path(with_organization: false)
|
||||
ids = traversal_ids.clone
|
||||
|
||||
ids.prepend(organization_id) if with_organization
|
||||
|
||||
"#{ids.join('/')}/"
|
||||
end
|
||||
|
||||
def use_traversal_ids?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMergeRequestCommitsMetadataIdOnMergeRequestDiffCommits < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
|
||||
# rubocop:disable Migration/PreventAddingColumns -- this column is required as
|
||||
# we will be querying data from `merge_request_commits_metadata` table using
|
||||
# this column
|
||||
def change
|
||||
add_column :merge_request_diff_commits, :merge_request_commits_metadata_id, :bigint, null: true
|
||||
end
|
||||
# rubocop:enable Migration/PreventAddingColumns
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PrepareAsyncIndexOnMergeRequestCommitsMetadataId < Gitlab::Database::Migration[2.2]
|
||||
milestone '18.0'
|
||||
|
||||
INDEX_NAME = 'index_mrdc_on_merge_request_commits_metadata_id'
|
||||
|
||||
# TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/issues/527227
|
||||
# rubocop:disable Migration/PreventIndexCreation -- this index is required as
|
||||
# we will be querying data from `merge_request_commits_metadata_id` and joining
|
||||
# by this column.
|
||||
def up
|
||||
prepare_async_index :merge_request_diff_commits, :merge_request_commits_metadata_id, name: INDEX_NAME,
|
||||
where: "merge_request_commit_metadata_id IS NOT NULL"
|
||||
end
|
||||
# rubocop:enable Migration/PreventIndexCreation
|
||||
|
||||
def down
|
||||
unprepare_async_index :merge_request_diff_commits, :merge_request_commits_metadata_id, name: INDEX_NAME
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
b4e384b22ad5ef6a42e6ccaf60a30e7cd7a73736da14d2d871bf64c47eef9ea8
|
||||
|
|
@ -0,0 +1 @@
|
|||
b2a963c276ecbfb2a9acdcb0506fa19581424499345504dc17c4a1ec3cffc226
|
||||
|
|
@ -17105,7 +17105,8 @@ CREATE TABLE merge_request_diff_commits (
|
|||
message text,
|
||||
trailers jsonb DEFAULT '{}'::jsonb,
|
||||
commit_author_id bigint,
|
||||
committer_id bigint
|
||||
committer_id bigint,
|
||||
merge_request_commits_metadata_id bigint
|
||||
);
|
||||
|
||||
CREATE TABLE merge_request_diff_details (
|
||||
|
|
|
|||
|
|
@ -125,23 +125,23 @@ To check indexing status:
|
|||
|
||||
{{< /tabs >}}
|
||||
|
||||
## Delete offline nodes automatically
|
||||
## Pause indexing
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have administrator access to the instance.
|
||||
|
||||
You can automatically delete Zoekt nodes that are offline for more than 12 hours
|
||||
and their related indices, repositories, and tasks.
|
||||
|
||||
To delete offline nodes automatically:
|
||||
To pause indexing for [exact code search](../../user/search/exact_code_search.md):
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > Search**.
|
||||
1. Expand **Exact code search configuration**.
|
||||
1. Select the **Delete offline nodes after 12 hours** checkbox.
|
||||
1. Select the **Pause indexing** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
When you pause indexing for exact code search, all changes in your repository are queued.
|
||||
To resume indexing, clear the **Pause indexing for exact code search** checkbox.
|
||||
|
||||
## Index root namespaces automatically
|
||||
|
||||
Prerequisites:
|
||||
|
|
@ -169,22 +169,38 @@ When you disable this setting:
|
|||
- Existing root namespaces remain indexed.
|
||||
- New root namespaces are no longer indexed.
|
||||
|
||||
## Pause indexing
|
||||
## Delete offline nodes automatically
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have administrator access to the instance.
|
||||
|
||||
To pause indexing for [exact code search](../../user/search/exact_code_search.md):
|
||||
You can automatically delete Zoekt nodes that are offline for more than 12 hours
|
||||
and their related indices, repositories, and tasks.
|
||||
To delete offline nodes automatically:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > Search**.
|
||||
1. Expand **Exact code search configuration**.
|
||||
1. Select the **Pause indexing** checkbox.
|
||||
1. Select the **Delete offline nodes after 12 hours** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
When you pause indexing for exact code search, all changes in your repository are queued.
|
||||
To resume indexing, clear the **Pause indexing for exact code search** checkbox.
|
||||
## Cache search results
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have administrator access to the instance.
|
||||
|
||||
You can cache search results for better performance.
|
||||
This feature is enabled by default and caches results for five minutes.
|
||||
|
||||
To cache search results:
|
||||
|
||||
1. On the left sidebar, at the bottom, select **Admin**.
|
||||
1. Select **Settings > Search**.
|
||||
1. Expand **Exact code search configuration**.
|
||||
1. Select the **Cache search results for five minutes** checkbox.
|
||||
1. Select **Save changes**.
|
||||
|
||||
## Set concurrent indexing tasks
|
||||
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@ for GitLab Ultimate.
|
|||
## Manage members in personal projects outside a group namespace
|
||||
|
||||
Personal projects are not located in top-level group namespaces. You can manage
|
||||
the users in each of your personal projects, but you cannot have more than five
|
||||
users in all of your personal projects.
|
||||
the users in each of your personal projects. You can have more than five
|
||||
users in your personal projects.
|
||||
|
||||
You should [move your personal project to a group](../tutorials/move_personal_project_to_group/_index.md)
|
||||
so that you can:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@
|
|||
|
||||
Create a file in `ActiveContext::Config.migrations_path`.
|
||||
|
||||
## Data types
|
||||
|
||||
ActiveContext supports several field types for defining collection schemas:
|
||||
|
||||
- `bigint`: For large numeric values (accepts `index: true/false`, defaults to `false`)
|
||||
- `boolean`: For boolean values (accepts `index: true/false`, defaults to `true`)
|
||||
- `keyword`: For exact-match searchable string fields (always indexed, no `index` option)
|
||||
- `text`: For full-text searchable content (accepts `index: true/false`, defaults to `false`)
|
||||
- `vector`: For embedding vectors (accepts `index: true/false`, defaults to `true`), requires `dimensions:` specification
|
||||
|
||||
## Migration to create a collection
|
||||
|
||||
```ruby
|
||||
|
|
@ -14,7 +24,9 @@ class CreateMergeRequests < ActiveContext::Migration[1.0]
|
|||
create_collection :merge_requests, number_of_partitions: 3 do |c|
|
||||
c.bigint :issue_id, index: true
|
||||
c.bigint :namespace_id, index: true
|
||||
c.prefix :traversal_ids
|
||||
c.boolean :is_draft
|
||||
c.keyword :traversal_ids
|
||||
c.text :description
|
||||
c.vector :embeddings, dimensions: 768
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Migrations are similiar to database migrations: they create collections, update
|
|||
|
||||
See [migrations](migrations.md) for more details.
|
||||
|
||||
A migration worker will apply migrations for the active connection. See [Migrations](how_it_works.md#migrations).
|
||||
A migration worker applies migrations for the active connection. See [Migrations](how_it_works.md#migrations).
|
||||
|
||||
If you want to run the worker manually, execute:
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ module ActiveContext
|
|||
fields << Field::Bigint.new(name, index: index)
|
||||
end
|
||||
|
||||
def boolean(name, index: true)
|
||||
fields << Field::Boolean.new(name, index: index)
|
||||
end
|
||||
|
||||
def keyword(name)
|
||||
fields << Field::Keyword.new(name, index: true)
|
||||
end
|
||||
|
|
@ -35,6 +39,7 @@ module ActiveContext
|
|||
end
|
||||
|
||||
class Bigint < Field; end
|
||||
class Boolean < Field; end
|
||||
class Keyword < Field; end
|
||||
class Text < Field; end
|
||||
class Vector < Field; end
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ module ActiveContext
|
|||
mappings[field.name] = case field
|
||||
when Field::Bigint
|
||||
{ type: 'long' }
|
||||
when Field::Boolean
|
||||
{ type: 'boolean' }
|
||||
when Field::Keyword
|
||||
{ type: 'keyword' }
|
||||
when Field::Text
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ module ActiveContext
|
|||
when Field::Bigint
|
||||
# Bigint is 8 bytes
|
||||
fixed_columns << [field, 8]
|
||||
when Field::Boolean
|
||||
# Boolean is 1 byte
|
||||
fixed_columns << [field, 1]
|
||||
when Field::Keyword, Field::Text
|
||||
# Text fields are variable width
|
||||
variable_columns << field
|
||||
|
|
@ -91,6 +94,8 @@ module ActiveContext
|
|||
case field
|
||||
when Field::Bigint
|
||||
table.bigint(field.name, **field.options.except(:index))
|
||||
when Field::Boolean
|
||||
table.boolean(field.name, **field.options.except(:index))
|
||||
when Field::Keyword, Field::Text
|
||||
table.text(field.name, **field.options.except(:index))
|
||||
when Field::Vector
|
||||
|
|
|
|||
|
|
@ -11884,6 +11884,9 @@ msgstr ""
|
|||
msgid "CVS|Only a project maintainer or owner can toggle this feature."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cache search results for %{label}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cadence"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -32386,6 +32389,9 @@ msgstr[1] ""
|
|||
msgid "Input host keys manually"
|
||||
msgstr ""
|
||||
|
||||
msgid "Input must be an integer between 0 and 9"
|
||||
msgstr ""
|
||||
|
||||
msgid "Input the remote repository URL"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53838,9 +53844,6 @@ msgstr ""
|
|||
msgid "Secrets|Delete secret"
|
||||
msgstr ""
|
||||
|
||||
msgid "Secrets|Description must be 200 characters or less."
|
||||
msgstr ""
|
||||
|
||||
msgid "Secrets|Edit %{id}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -53910,6 +53913,9 @@ msgstr ""
|
|||
msgid "Secrets|The name should be unique within this project."
|
||||
msgstr ""
|
||||
|
||||
msgid "Secrets|This field is required and must be 200 characters or less."
|
||||
msgstr ""
|
||||
|
||||
msgid "Secrets|To confirm, enter %{secretName}:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -69028,9 +69034,6 @@ msgstr ""
|
|||
msgid "WorkItem|Requirement"
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Requirements"
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Reset template"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -69157,6 +69160,12 @@ msgstr ""
|
|||
msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Something went wrong while fetching more related vulnerabilities."
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Something went wrong while fetching related vulnerabilities."
|
||||
msgstr ""
|
||||
|
||||
msgid "WorkItem|Something went wrong while fetching the %{workItemType}. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ RSpec.describe 'Database schema',
|
|||
merge_requests_compliance_violations: %w[target_project_id],
|
||||
merge_request_diffs: %w[project_id],
|
||||
merge_request_diff_files: %w[project_id],
|
||||
merge_request_diff_commits: %w[commit_author_id committer_id],
|
||||
merge_request_diff_commits: %w[commit_author_id committer_id merge_request_commits_metadata_id],
|
||||
# merge_request_diff_commits_b5377a7a34 is the temporary table for the merge_request_diff_commits partitioning
|
||||
# backfill. It will get foreign keys after the partitioning is finished.
|
||||
merge_request_diff_commits_b5377a7a34: %w[merge_request_diff_id commit_author_id committer_id project_id],
|
||||
|
|
|
|||
|
|
@ -7,9 +7,17 @@ import CreateWorkItem from '~/work_items/components/create_work_item.vue';
|
|||
import CreateWorkItemModal from '~/work_items/components/create_work_item_modal.vue';
|
||||
import {
|
||||
WORK_ITEM_TYPE_NAME_EPIC,
|
||||
WORK_ITEM_TYPE_NAME_INCIDENT,
|
||||
WORK_ITEM_TYPE_NAME_ISSUE,
|
||||
WORK_ITEM_TYPE_NAME_KEY_RESULT,
|
||||
WORK_ITEM_TYPE_NAME_OBJECTIVE,
|
||||
WORK_ITEM_TYPE_NAME_REQUIREMENTS,
|
||||
WORK_ITEM_TYPE_NAME_TASK,
|
||||
WORK_ITEM_TYPE_NAME_TEST_CASE,
|
||||
WORK_ITEM_TYPE_NAME_TICKET,
|
||||
WORK_ITEM_TYPE_ROUTE_EPIC,
|
||||
WORK_ITEM_TYPE_ROUTE_ISSUE,
|
||||
WORK_ITEM_TYPE_ROUTE_WORK_ITEM,
|
||||
WORK_ITEMS_TYPE_MAP,
|
||||
} from '~/work_items/constants';
|
||||
import CreateWorkItemCancelConfirmationModal from '~/work_items/components/create_work_item_cancel_confirmation_modal.vue';
|
||||
|
||||
|
|
@ -152,24 +160,38 @@ describe('CreateWorkItemModal', () => {
|
|||
expect(findCreateModal().props('visible')).toBe(false);
|
||||
});
|
||||
|
||||
for (const values of Object.values(WORK_ITEMS_TYPE_MAP)) {
|
||||
it(`has link to new work item page in modal header for ${values.value}`, async () => {
|
||||
createComponent({ preselectedWorkItemType: values.value });
|
||||
|
||||
const routeParamName = values.routeParamName || WORK_ITEM_TYPE_ROUTE_WORK_ITEM;
|
||||
|
||||
it.each`
|
||||
workItemType | routeParamName
|
||||
${WORK_ITEM_TYPE_NAME_EPIC} | ${WORK_ITEM_TYPE_ROUTE_EPIC}
|
||||
${WORK_ITEM_TYPE_NAME_ISSUE} | ${WORK_ITEM_TYPE_ROUTE_ISSUE}
|
||||
${WORK_ITEM_TYPE_NAME_INCIDENT} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_KEY_RESULT} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_OBJECTIVE} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_REQUIREMENTS} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_TASK} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_TEST_CASE} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
${WORK_ITEM_TYPE_NAME_TICKET} | ${WORK_ITEM_TYPE_ROUTE_WORK_ITEM}
|
||||
`(
|
||||
`has link to new work item page in modal header for $workItemType`,
|
||||
async ({ workItemType, routeParamName }) => {
|
||||
createComponent({ preselectedWorkItemType: workItemType });
|
||||
await waitForPromises();
|
||||
|
||||
expect(findOpenInFullPageButton().attributes().href).toBe(
|
||||
`/full-path/-/${routeParamName}/new`,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
describe('when there is a related item', () => {
|
||||
beforeEach(async () => {
|
||||
createComponent({
|
||||
relatedItem: { id: 'gid://gitlab/WorkItem/843', type: 'Epic', reference: 'flightjs#53' },
|
||||
relatedItem: {
|
||||
id: 'gid://gitlab/WorkItem/843',
|
||||
type: 'Epic',
|
||||
reference: 'flightjs#53',
|
||||
webUrl: 'http://gdk.test:3000/flightjs/Flight',
|
||||
},
|
||||
});
|
||||
await waitForPromises();
|
||||
await nextTick();
|
||||
|
|
|
|||
|
|
@ -21,8 +21,12 @@ import {
|
|||
WORK_ITEM_TYPE_NAME_EPIC,
|
||||
WORK_ITEM_TYPE_NAME_INCIDENT,
|
||||
WORK_ITEM_TYPE_NAME_ISSUE,
|
||||
WORK_ITEM_TYPE_NAME_KEY_RESULT,
|
||||
WORK_ITEM_TYPE_NAME_OBJECTIVE,
|
||||
WORK_ITEM_TYPE_NAME_REQUIREMENTS,
|
||||
WORK_ITEM_TYPE_NAME_TASK,
|
||||
WORK_ITEMS_TYPE_MAP,
|
||||
WORK_ITEM_TYPE_NAME_TEST_CASE,
|
||||
WORK_ITEM_TYPE_NAME_TICKET,
|
||||
} from '~/work_items/constants';
|
||||
import { setNewWorkItemCache } from '~/work_items/graphql/cache_utils';
|
||||
import namespaceWorkItemTypesQuery from '~/work_items/graphql/namespace_work_item_types.query.graphql';
|
||||
|
|
@ -187,14 +191,24 @@ describe('Create work item component', () => {
|
|||
expect(setNewWorkItemCache).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each(Object.keys(WORK_ITEMS_TYPE_MAP))(
|
||||
'Clears cache on cancel for workItemType: %s with the correct data',
|
||||
async (type) => {
|
||||
const typeName = WORK_ITEMS_TYPE_MAP[type].value;
|
||||
it.each`
|
||||
workItemType
|
||||
${WORK_ITEM_TYPE_NAME_EPIC}
|
||||
${WORK_ITEM_TYPE_NAME_INCIDENT}
|
||||
${WORK_ITEM_TYPE_NAME_ISSUE}
|
||||
${WORK_ITEM_TYPE_NAME_KEY_RESULT}
|
||||
${WORK_ITEM_TYPE_NAME_OBJECTIVE}
|
||||
${WORK_ITEM_TYPE_NAME_REQUIREMENTS}
|
||||
${WORK_ITEM_TYPE_NAME_TASK}
|
||||
${WORK_ITEM_TYPE_NAME_TEST_CASE}
|
||||
${WORK_ITEM_TYPE_NAME_TICKET}
|
||||
`(
|
||||
'Clears cache on cancel for workItemType=$workItemType with the correct data',
|
||||
async ({ workItemType }) => {
|
||||
const expectedWorkItemTypeData = namespaceWorkItemTypes.find(
|
||||
({ name }) => name === typeName,
|
||||
({ name }) => name === workItemType,
|
||||
);
|
||||
createComponent({ preselectedWorkItemType: typeName });
|
||||
createComponent({ preselectedWorkItemType: workItemType });
|
||||
await waitForPromises();
|
||||
|
||||
findCancelButton().vm.$emit('click');
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ describe('WorkItemCreatedUpdated component', () => {
|
|||
|
||||
expect(findWorkItemTypeIcon().props()).toMatchObject({
|
||||
showText: true,
|
||||
workItemIconName: workItem.workItemType.iconName,
|
||||
workItemType: workItem.workItemType.name,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,32 +18,25 @@ describe('Work Item type component', () => {
|
|||
const findIcon = () => wrapper.findComponent(GlIcon);
|
||||
|
||||
describe.each`
|
||||
workItemType | workItemIconName | iconName | text | showTooltipOnHover | iconVariant
|
||||
${'TASK'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'default'}
|
||||
${''} | ${'issue-type-task'} | ${'issue-type-task'} | ${''} | ${true} | ${'default'}
|
||||
${'ISSUE'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'default'}
|
||||
${''} | ${'issue-type-issue'} | ${'issue-type-issue'} | ${''} | ${true} | ${'default'}
|
||||
${'REQUIREMENT'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true} | ${'default'}
|
||||
${'INCIDENT'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'default'}
|
||||
${'TEST_CASE'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'default'}
|
||||
${'random-issue-type'} | ${''} | ${'issue-type-issue'} | ${''} | ${true} | ${'default'}
|
||||
${'Task'} | ${''} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'default'}
|
||||
${'Issue'} | ${''} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'default'}
|
||||
${'Requirement'} | ${''} | ${'issue-type-requirements'} | ${'Requirements'} | ${true} | ${'default'}
|
||||
${'Incident'} | ${''} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'default'}
|
||||
${'Test_case'} | ${''} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'default'}
|
||||
${'Objective'} | ${''} | ${'issue-type-objective'} | ${'Objective'} | ${true} | ${'default'}
|
||||
${'Key Result'} | ${''} | ${'issue-type-keyresult'} | ${'Key result'} | ${true} | ${'subtle'}
|
||||
workItemType | iconName | text | showTooltipOnHover | iconVariant
|
||||
${'TASK'} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'default'}
|
||||
${'ISSUE'} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'default'}
|
||||
${'REQUIREMENT'} | ${'issue-type-requirements'} | ${'Requirement'} | ${true} | ${'default'}
|
||||
${'INCIDENT'} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'default'}
|
||||
${'TEST_CASE'} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'default'}
|
||||
${'random-issue-type'} | ${'issue-type-issue'} | ${''} | ${true} | ${'default'}
|
||||
${'Task'} | ${'issue-type-task'} | ${'Task'} | ${false} | ${'default'}
|
||||
${'Issue'} | ${'issue-type-issue'} | ${'Issue'} | ${true} | ${'default'}
|
||||
${'Requirement'} | ${'issue-type-requirements'} | ${'Requirement'} | ${true} | ${'default'}
|
||||
${'Incident'} | ${'issue-type-incident'} | ${'Incident'} | ${false} | ${'default'}
|
||||
${'Test_case'} | ${'issue-type-test-case'} | ${'Test case'} | ${true} | ${'default'}
|
||||
${'Objective'} | ${'issue-type-objective'} | ${'Objective'} | ${true} | ${'default'}
|
||||
${'Key Result'} | ${'issue-type-keyresult'} | ${'Key result'} | ${true} | ${'subtle'}
|
||||
`(
|
||||
'with workItemType set to "$workItemType" and workItemIconName set to "$workItemIconName"',
|
||||
({ workItemType, workItemIconName, iconName, text, showTooltipOnHover, iconVariant }) => {
|
||||
'with workItemType set to "$workItemType"',
|
||||
({ workItemType, iconName, text, showTooltipOnHover, iconVariant }) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
workItemType,
|
||||
workItemIconName,
|
||||
showTooltipOnHover,
|
||||
iconVariant,
|
||||
});
|
||||
createComponent({ workItemType, showTooltipOnHover, iconVariant });
|
||||
});
|
||||
|
||||
it(`renders icon with name '${iconName}'`, () => {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import {
|
|||
markdownPreviewPath,
|
||||
newWorkItemPath,
|
||||
isReference,
|
||||
getWorkItemIcon,
|
||||
workItemRoadmapPath,
|
||||
saveToggleToLocalStorage,
|
||||
getToggleFromLocalStorage,
|
||||
|
|
@ -185,7 +184,7 @@ describe('newWorkItemPath', () => {
|
|||
|
||||
it('returns correct path for workItemType', () => {
|
||||
expect(
|
||||
newWorkItemPath({ fullPath: 'group/project', workItemTypeName: WORK_ITEM_TYPE_ENUM_ISSUE }),
|
||||
newWorkItemPath({ fullPath: 'group/project', workItemType: WORK_ITEM_TYPE_NAME_ISSUE }),
|
||||
).toBe('/foobar/group/project/-/issues/new');
|
||||
});
|
||||
|
||||
|
|
@ -194,7 +193,7 @@ describe('newWorkItemPath', () => {
|
|||
newWorkItemPath({
|
||||
fullPath: 'group',
|
||||
isGroup: true,
|
||||
workItemTypeName: WORK_ITEM_TYPE_ENUM_EPIC,
|
||||
workItemType: WORK_ITEM_TYPE_NAME_EPIC,
|
||||
}),
|
||||
).toBe('/foobar/groups/group/-/epics/new');
|
||||
});
|
||||
|
|
@ -223,12 +222,6 @@ describe('convertTypeEnumToName', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getWorkItemIcon', () => {
|
||||
it.each(['epic', 'issue-type-epic'])('returns epic icon in case of %s', (icon) => {
|
||||
expect(getWorkItemIcon(icon)).toBe('epic');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isReference', () => {
|
||||
it.each`
|
||||
referenceId | result
|
||||
|
|
|
|||
|
|
@ -33,4 +33,17 @@ RSpec.describe NumbersHelper do
|
|||
it { is_expected.to eq(expected_result) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#number_in_words' do
|
||||
it 'returns the correct word for the given number' do
|
||||
expect(number_in_words(0)).to eq('zero')
|
||||
expect(number_in_words(1)).to eq('one')
|
||||
expect(number_in_words(9)).to eq('nine')
|
||||
end
|
||||
|
||||
it 'raises an error for numbers outside the range 0-9' do
|
||||
expect { number_in_words(-1) }.to raise_error(ArgumentError, _('Input must be an integer between 0 and 9'))
|
||||
expect { number_in_words(10) }.to raise_error(ArgumentError, _('Input must be an integer between 0 and 9'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -995,6 +995,26 @@ RSpec.describe Namespace, feature_category: :groups_and_projects do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'traversal_path' do
|
||||
it 'formats the traversal ids with slashes' do
|
||||
expect(namespace.traversal_path).to eq("#{namespace.id}/")
|
||||
end
|
||||
|
||||
context 'for subgroup' do
|
||||
let(:subgroup) { Group.new(traversal_ids: [1, 2, 3], organization_id: 1111) }
|
||||
|
||||
it 'formats the traversal ids with slashes' do
|
||||
expect(subgroup.traversal_path).to eq("1/2/3/")
|
||||
end
|
||||
|
||||
context 'when with_organization option is enabled' do
|
||||
it 'prepends the organization id' do
|
||||
expect(subgroup.traversal_path(with_organization: true)).to eq("1111/1/2/3/")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "after_commit :expire_child_caches" do
|
||||
let(:namespace) { create(:group, organization: organization) }
|
||||
|
||||
|
|
|
|||
|
|
@ -4,18 +4,25 @@ module ClickHouseHelpers
|
|||
extend ActiveRecord::ConnectionAdapters::Quoting
|
||||
|
||||
def insert_events_into_click_house(events = Event.all)
|
||||
clickhouse_fixture(:events, events.map do |event|
|
||||
{
|
||||
id: event.id,
|
||||
path: event.project.reload.project_namespace.traversal_path,
|
||||
author_id: event.author_id,
|
||||
target_id: event.target_id,
|
||||
target_type: event.target_type,
|
||||
action: Event.actions[event.action],
|
||||
created_at: event.created_at,
|
||||
updated_at: event.updated_at
|
||||
}
|
||||
end)
|
||||
# Insert into both events table until legacy table is removed
|
||||
%i[events events_new].each do |clickhouse_table_name|
|
||||
clickhouse_fixture(clickhouse_table_name, events.map do |event|
|
||||
project_namespace = event.project.reload.project_namespace
|
||||
include_organization_on_path = clickhouse_table_name == :events_new
|
||||
path = project_namespace.traversal_path(with_organization: include_organization_on_path)
|
||||
|
||||
{
|
||||
id: event.id,
|
||||
path: path,
|
||||
author_id: event.author_id,
|
||||
target_id: event.target_id,
|
||||
target_type: event.target_type,
|
||||
action: Event.actions[event.action],
|
||||
created_at: event.created_at,
|
||||
updated_at: event.updated_at
|
||||
}
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CyclomaticComplexity -- the method is straightforward, just a lot of &.
|
||||
|
|
|
|||
|
|
@ -2394,7 +2394,6 @@
|
|||
- './ee/spec/workers/geo/verification_state_backfill_service_spec.rb'
|
||||
- './ee/spec/workers/geo/verification_state_backfill_worker_spec.rb'
|
||||
- './ee/spec/workers/geo/verification_timeout_worker_spec.rb'
|
||||
- './ee/spec/workers/geo/verification_worker_spec.rb'
|
||||
- './ee/spec/workers/group_saml_group_sync_worker_spec.rb'
|
||||
- './ee/spec/workers/groups/create_event_worker_spec.rb'
|
||||
- './ee/spec/workers/groups/export_memberships_worker_spec.rb'
|
||||
|
|
|
|||
|
|
@ -251,7 +251,6 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
|
|||
'Geo::VerificationBatchWorker' => 0,
|
||||
'Geo::VerificationStateBackfillWorker' => false,
|
||||
'Geo::VerificationTimeoutWorker' => false,
|
||||
'Geo::VerificationWorker' => 3,
|
||||
'Gitlab::BitbucketImport::AdvanceStageWorker' => 6,
|
||||
'Gitlab::BitbucketImport::Stage::FinishImportWorker' => 6,
|
||||
'Gitlab::BitbucketImport::Stage::ImportIssuesWorker' => 6,
|
||||
|
|
|
|||
Loading…
Reference in New Issue