Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a5f5c99d4a
commit
e4a70049b6
|
|
@ -116,7 +116,6 @@ Gitlab/AvoidGitlabInstanceChecks:
|
|||
- 'ee/lib/gitlab/llm/tanuki_bot.rb'
|
||||
- 'ee/lib/gitlab/manual_quarterly_co_term_banner.rb'
|
||||
- 'ee/lib/gitlab/sitemaps/generator.rb'
|
||||
- 'ee/lib/sidebars/groups/menus/trial_widget_menu.rb'
|
||||
- 'ee/lib/sidebars/user_settings/menus/profile_billing_menu.rb'
|
||||
- 'ee/lib/tasks/gitlab/elastic.rake'
|
||||
- 'ee/spec/factories/gitlab_subscriptions.rb'
|
||||
|
|
|
|||
|
|
@ -219,21 +219,6 @@ Layout/ArgumentAlignment:
|
|||
- 'ee/app/graphql/mutations/security_policy/assign_security_policy_project.rb'
|
||||
- 'ee/app/graphql/mutations/security_policy/commit_scan_execution_policy.rb'
|
||||
- 'ee/app/graphql/mutations/security_policy/create_security_policy_project.rb'
|
||||
- 'ee/app/graphql/mutations/security_policy/unassign_security_policy_project.rb'
|
||||
- 'ee/app/graphql/mutations/users/abuse/namespace_bans/destroy.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/confirm.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/create_external_issue_link.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/destroy_external_issue_link.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/dismiss.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/resolve.rb'
|
||||
- 'ee/app/graphql/mutations/vulnerabilities/revert_to_detected.rb'
|
||||
- 'ee/app/graphql/resolvers/alert_management/payload_alert_field_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/analytics/contribution_analytics/contributions_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/analytics/devops_adoption/enabled_namespaces_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/analytics/devops_adoption/snapshots_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/app_sec/dast/profile_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/board_groupings/epics_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/boards/board_list_epics_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/incident_management/escalation_policies_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/incident_management/issuable_resource_links_resolver.rb'
|
||||
- 'ee/app/graphql/resolvers/incident_management/oncall_rotations_resolver.rb'
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export default {
|
|||
{
|
||||
key: 'buttons',
|
||||
label: '',
|
||||
tdClass: `${DEFAULT_TD_CLASSES} gl-white-space-nowrap`,
|
||||
tdClass: `${DEFAULT_TD_CLASSES} gl-whitespace-nowrap`,
|
||||
},
|
||||
],
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ export default {
|
|||
{
|
||||
key: 'actions',
|
||||
label: __('Actions'),
|
||||
tdClass: 'gl-lg-w-1px gl-white-space-nowrap',
|
||||
thClass: 'gl-lg-w-1px gl-white-space-nowrap',
|
||||
tdClass: 'gl-lg-w-1px gl-whitespace-nowrap',
|
||||
thClass: 'gl-lg-w-1px gl-whitespace-nowrap',
|
||||
},
|
||||
],
|
||||
modal: {
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ export default {
|
|||
v-if="item.iteration"
|
||||
data-testid="issue-iteration"
|
||||
:iteration="item.iteration"
|
||||
class="gl-align-bottom gl-white-space-nowrap"
|
||||
class="gl-align-bottom gl-whitespace-nowrap"
|
||||
/>
|
||||
<issue-due-date
|
||||
v-if="item.dueDate"
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ export default {
|
|||
v-if="!isSwimlanesOn"
|
||||
ref="list"
|
||||
v-bind="draggableOptions"
|
||||
class="boards-list gl-w-full gl-py-5 gl-pl-0 gl-pr-5 xl:gl-pl-3 xl:gl-pr-6 gl-white-space-nowrap gl-overflow-x-auto"
|
||||
class="boards-list gl-w-full gl-py-5 gl-pl-0 gl-pr-5 xl:gl-pl-3 xl:gl-pr-6 gl-whitespace-nowrap gl-overflow-x-auto"
|
||||
@end="updateListPosition"
|
||||
>
|
||||
<board-column
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ export default {
|
|||
<div class="js-pipeline-graph">
|
||||
<div
|
||||
ref="mainPipelineContainer"
|
||||
class="pipeline-graph gl-display-flex gl-position-relative gl-white-space-nowrap gl-rounded-lg"
|
||||
class="pipeline-graph gl-display-flex gl-position-relative gl-whitespace-nowrap gl-rounded-lg"
|
||||
:class="{
|
||||
'pipeline-graph-container gl-bg-gray-10 gl-pipeline-min-h gl-align-items-flex-start gl-pt-3 gl-pb-8 gl-mt-3 gl-overflow-auto': !isLinkedPipeline,
|
||||
'gl-bg-gray-50 gl-sm-ml-5': isLinkedPipeline,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default {
|
|||
>
|
||||
<p
|
||||
v-if="duration"
|
||||
class="gl-display-inline-flex gl-align-items-center gl-text-secondary gl-m-0 gl-white-space-nowrap"
|
||||
class="gl-display-inline-flex gl-align-items-center gl-text-secondary gl-m-0 gl-whitespace-nowrap"
|
||||
data-testid="duration"
|
||||
>
|
||||
<gl-icon name="timer" class="gl-mr-2" :size="12" />
|
||||
|
|
@ -50,7 +50,7 @@ export default {
|
|||
|
||||
<p
|
||||
v-if="finishedTime"
|
||||
class="gl-display-inline-flex gl-align-items-center gl-text-secondary gl-m-0 gl-white-space-nowrap"
|
||||
class="gl-display-inline-flex gl-align-items-center gl-text-secondary gl-m-0 gl-whitespace-nowrap"
|
||||
data-testid="finished-at"
|
||||
>
|
||||
<gl-icon name="calendar" class="gl-mr-2" :size="12" data-testid="calendar-icon" />
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export default {
|
|||
{
|
||||
key: 'actions',
|
||||
label: __('Actions'),
|
||||
tdClass: 'gl-text-right gl-white-space-nowrap',
|
||||
tdClass: 'gl-text-right gl-whitespace-nowrap',
|
||||
thClass: `gl-text-right gl-w-1/20`,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ export default {
|
|||
:aria-label="linkCanonicalSrc"
|
||||
:title="linkCanonicalSrc"
|
||||
target="_blank"
|
||||
class="gl-px-3 gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis"
|
||||
class="gl-px-3 gl-overflow-hidden gl-whitespace-nowrap gl-text-overflow-ellipsis"
|
||||
>
|
||||
{{ linkCanonicalSrc }}
|
||||
</gl-link>
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ export default {
|
|||
:aria-label="mediaCanonicalSrc"
|
||||
:title="mediaCanonicalSrc"
|
||||
target="_blank"
|
||||
class="gl-px-3 gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis"
|
||||
class="gl-px-3 gl-overflow-hidden gl-whitespace-nowrap gl-text-overflow-ellipsis"
|
||||
>
|
||||
{{ mediaCanonicalSrc }}
|
||||
</gl-link>
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ export default {
|
|||
:tippy-options="$options.tippyOptions"
|
||||
>
|
||||
<gl-button-group class="gl-display-flex gl-align-items-center">
|
||||
<span class="gl-py-2 gl-px-3 gl-text-secondary gl-white-space-nowrap">
|
||||
<span class="gl-py-2 gl-px-3 gl-text-secondary gl-whitespace-nowrap">
|
||||
{{ __('Display as:') }}
|
||||
</span>
|
||||
<gl-collapsible-listbox
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ export default {
|
|||
</div>
|
||||
|
||||
<div
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-pl-3 gl-gap-2 gl-white-space-nowrap"
|
||||
class="gl-display-flex gl-flex-wrap gl-align-items-center gl-pl-3 gl-gap-2 gl-whitespace-nowrap"
|
||||
>
|
||||
<gl-sprintf :message="__('From line %{line1} to %{line2}')">
|
||||
<template #line1>
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ export default {
|
|||
>
|
||||
<template #default="{ timeAgo }">
|
||||
<gl-icon name="calendar" class="gl-mr-2" />
|
||||
<span class="gl-mr-2 gl-white-space-nowrap">
|
||||
<span class="gl-mr-2 gl-whitespace-nowrap">
|
||||
<gl-sprintf :message="timeagoText">
|
||||
<template #timeago>{{ timeAgo }}</template>
|
||||
<template #username>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export default {
|
|||
:avatar-size="24"
|
||||
badge-tooltip-prop="name"
|
||||
:badge-sr-only-text="authorCollapsedTooltip"
|
||||
class="gl-white-space-nowrap gl-mr-3"
|
||||
class="gl-whitespace-nowrap gl-mr-3"
|
||||
>
|
||||
<template #avatar="{ avatar }">
|
||||
<gl-avatar-link v-gl-tooltip :href="avatar.webUrl" :title="avatar.name">
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ export default {
|
|||
>
|
||||
<template #default="{ timeAgo }">
|
||||
<gl-icon name="calendar" class="gl-mr-2" />
|
||||
<span class="gl-mr-2 gl-white-space-nowrap">
|
||||
<span class="gl-mr-2 gl-whitespace-nowrap">
|
||||
<gl-sprintf :message="timeStamp">
|
||||
<template #timeago>{{ timeAgo }}</template>
|
||||
</gl-sprintf>
|
||||
|
|
|
|||
|
|
@ -43,21 +43,21 @@ export const ENVIRONMENT_DETAILS_TABLE_FIELDS = [
|
|||
key: 'created',
|
||||
label: __('Created'),
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
tdClass: '!gl-align-middle gl-whitespace-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'deployed',
|
||||
label: __('Deployed'),
|
||||
columnClass: 'gl-w-2/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
tdClass: '!gl-align-middle gl-whitespace-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: __('Actions'),
|
||||
columnClass: 'gl-w-3/20',
|
||||
tdClass: '!gl-align-middle gl-white-space-nowrap',
|
||||
tdClass: '!gl-align-middle gl-whitespace-nowrap',
|
||||
thClass: 'gl-border-t-none!',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export default {
|
|||
{
|
||||
key: 'relation',
|
||||
label: __('Type'),
|
||||
tdClass: 'gl-white-space-nowrap',
|
||||
tdClass: 'gl-whitespace-nowrap',
|
||||
},
|
||||
{
|
||||
key: 'source_title',
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export default {
|
|||
{
|
||||
key: 'type',
|
||||
label: __('Type'),
|
||||
tdClass: 'gl-white-space-nowrap',
|
||||
tdClass: 'gl-whitespace-nowrap',
|
||||
},
|
||||
{
|
||||
key: 'title',
|
||||
|
|
@ -20,7 +20,7 @@ export default {
|
|||
{
|
||||
key: 'provider_url',
|
||||
label: __('URL'),
|
||||
tdClass: 'gl-white-space-nowrap',
|
||||
tdClass: 'gl-whitespace-nowrap',
|
||||
},
|
||||
{
|
||||
key: 'details',
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gl-white-space-nowrap gl-display-inline-flex gl-align-items-center gl-gap-3">
|
||||
<div class="gl-whitespace-nowrap gl-display-inline-flex gl-align-items-center gl-gap-3">
|
||||
<template v-if="isProjectCreationAllowed">
|
||||
<gl-button-group v-if="showImportActions">
|
||||
<gl-button
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<p class="gl-text-gray-900 gl-white-space-nowrap gl-mt-3">
|
||||
<p class="gl-text-gray-900 gl-whitespace-nowrap gl-mt-3">
|
||||
{{ s__('ImportProjects|Select the repositories you want to import') }}
|
||||
</p>
|
||||
<template v-if="hasIncompatibleRepos">
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ export default {
|
|||
<td data-testid="import-status-indicator">
|
||||
<import-status :project-id="importedProjectId" :status="importStatus" :stats="stats" />
|
||||
</td>
|
||||
<td data-testid="actions" class="gl-white-space-nowrap">
|
||||
<td data-testid="actions" class="gl-whitespace-nowrap">
|
||||
<gl-tooltip :target="() => $refs.cancelButton.$el">
|
||||
<div class="gl-text-left">
|
||||
<p class="gl-mb-5 gl-font-weight-bold">{{ s__('ImportProjects|Cancel import') }}</p>
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ export default {
|
|||
:closed="isIssueClosed"
|
||||
tooltip-placement="top"
|
||||
class="gl-mr-4"
|
||||
css-class="gl-display-flex gl-white-space-nowrap"
|
||||
css-class="gl-display-flex gl-whitespace-nowrap"
|
||||
/>
|
||||
<issue-weight
|
||||
v-if="issue.weight"
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ export const TABS = [
|
|||
},
|
||||
{
|
||||
namespace: MEMBER_TYPES.invite,
|
||||
title: __('Invited'),
|
||||
title: s__('Members|Pending invitations'),
|
||||
requiredPermissions: ['canManageMembers'],
|
||||
queryParamValue: TAB_QUERY_PARAM_VALUES.invite,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ export default {
|
|||
<a
|
||||
v-safe-html:[$options.safeHtmlConfig]="titleHtml"
|
||||
href="#top"
|
||||
class="gl-display-none gl-lg-display-block gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-ml-1 gl-mr-2 gl-text-black-normal"
|
||||
class="gl-display-none gl-lg-display-block gl-font-weight-bold gl-overflow-hidden gl-whitespace-nowrap gl-text-overflow-ellipsis gl-my-0 gl-ml-1 gl-mr-2 gl-text-black-normal"
|
||||
></a>
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<gl-sprintf :message="__('%{source} %{copyButton} into %{target}')">
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ export default {
|
|||
<div
|
||||
v-gl-tooltip="{ title: tag.name }"
|
||||
data-testid="name"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-whitespace-nowrap"
|
||||
:class="mobileClasses"
|
||||
>
|
||||
{{ tag.name }}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default {
|
|||
<div class="gl-display-flex gl-align-items-center">
|
||||
<div
|
||||
data-testid="name"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap"
|
||||
class="gl-text-overflow-ellipsis gl-overflow-hidden gl-whitespace-nowrap"
|
||||
>
|
||||
{{ tag.name }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export default {
|
|||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'issue-token gl-display-inline-flex gl-align-items-stretch gl-max-w-full gl-line-height-24 gl-white-space-nowrap': isCondensed,
|
||||
'issue-token gl-display-inline-flex gl-align-items-stretch gl-max-w-full gl-line-height-24 gl-whitespace-nowrap': isCondensed,
|
||||
'flex-row issuable-info-container': !isCondensed,
|
||||
}"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ export default {
|
|||
<div class="gl-display-flex gl-flex-direction-column">
|
||||
<span
|
||||
v-safe-html="highlightedItemName(item)"
|
||||
class="gl-font-weight-bold gl-white-space-nowrap"
|
||||
class="gl-font-weight-bold gl-whitespace-nowrap"
|
||||
data-testid="item-title"
|
||||
></span>
|
||||
<span class="gl-font-sm gl-text-gray-700" data-testid="item-namespace">
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export default {
|
|||
class="gl-display-flex gl-align-items-center gl-justify-content-space-between hide-collapsed"
|
||||
>
|
||||
<span
|
||||
class="gl-overflow-hidden gl-text-overflow-ellipsis gl-white-space-nowrap"
|
||||
class="gl-overflow-hidden gl-text-overflow-ellipsis gl-whitespace-nowrap"
|
||||
:title="value"
|
||||
>
|
||||
<gl-sprintf :message="$options.i18n.templateText">
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default {
|
|||
<span
|
||||
class="show-hover-layover-hint gl-opacity-0 gl-justify-content-end gl-align-items-center gl-display-none gl-sm-display-flex"
|
||||
>
|
||||
<span class="gl-text-gray-700 gl-white-space-nowrap" data-testid="overlay-message">
|
||||
<span class="gl-text-gray-700 gl-whitespace-nowrap" data-testid="overlay-message">
|
||||
<gl-sprintf :message="textMessage">
|
||||
<template #kbd="{ content }">
|
||||
<kbd class="gl-font-base gl-pb-3 vertical-align-normalization gl-align-middle">
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ export default {
|
|||
</p>
|
||||
</div>
|
||||
<p
|
||||
class="gl-m-0 gl-font-size-h-display gl-font-weight-bold gl-white-space-nowrap"
|
||||
class="gl-m-0 gl-font-size-h-display gl-font-weight-bold gl-whitespace-nowrap"
|
||||
data-testid="total-usage"
|
||||
>
|
||||
{{ totalUsage }}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export default {
|
|||
<div>
|
||||
<div class="gl-display-flex gl-mt-7">
|
||||
<div class="gl-flex-basis-0 gl-mr-7">
|
||||
<h4 class="gl-min-width-fit-content gl-white-space-nowrap">
|
||||
<h4 class="gl-min-width-fit-content gl-whitespace-nowrap">
|
||||
{{ $options.translations.formLabel }}
|
||||
</h4>
|
||||
<gl-sprintf :message="$options.translations.formSubtitle" class="gl-text-gray-500">
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export default {
|
|||
@click="$emit('ciStatusBadgeClick')"
|
||||
>
|
||||
<span class="ci-icon-gl-icon-wrapper"><gl-icon :name="icon" /></span
|
||||
><span v-if="showStatusText" class="gl-mx-2 gl-white-space-nowrap" data-testid="ci-icon-text">{{
|
||||
><span v-if="showStatusText" class="gl-mx-2 gl-whitespace-nowrap" data-testid="ci-icon-text">{{
|
||||
status.text
|
||||
}}</span>
|
||||
</gl-badge>
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ export default {
|
|||
:class="item.name ? 'gl-text-truncate' : 'gl-italic gl-gray-400'"
|
||||
>{{ item.text }}</span
|
||||
>
|
||||
<span class="gl-ml-auto gl-white-space-nowrap" aria-hidden="true">
|
||||
<span class="gl-ml-auto gl-whitespace-nowrap" aria-hidden="true">
|
||||
<span class="gl-text-green-600">+{{ item.added }}</span>
|
||||
<span class="gl-text-red-500">-{{ item.removed }}</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export const tdClass =
|
||||
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
|
||||
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-whitespace-nowrap';
|
||||
export const bodyTrClass =
|
||||
'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-gray-50 gl-hover-border-b-solid';
|
||||
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ export default {
|
|||
</div>
|
||||
<div
|
||||
v-if="project.updatedAt"
|
||||
class="gl-font-sm gl-white-space-nowrap gl-text-secondary gl-mt-3 gl-md-mt-0"
|
||||
class="gl-font-sm gl-whitespace-nowrap gl-text-secondary gl-mt-3 gl-md-mt-0"
|
||||
>
|
||||
<span>{{ $options.i18n.updated }}</span>
|
||||
<time-ago-tooltip :time="project.updatedAt" />
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export default {
|
|||
>
|
||||
<div class="issue-sticky-header-text gl-display-flex gl-align-items-baseline gl-mx-auto">
|
||||
<gl-badge
|
||||
class="gl-white-space-nowrap gl-mr-3 gl-align-self-center"
|
||||
class="gl-whitespace-nowrap gl-mr-3 gl-align-self-center"
|
||||
:variant="badgeVariant"
|
||||
>
|
||||
<gl-icon v-if="statusIcon" class="gl-sm-display-none" :name="statusIcon" />
|
||||
|
|
@ -102,12 +102,12 @@ export default {
|
|||
</gl-badge>
|
||||
<confidentiality-badge
|
||||
v-if="issuable.confidential"
|
||||
class="gl-white-space-nowrap gl-mr-3 gl-align-self-center"
|
||||
class="gl-whitespace-nowrap gl-mr-3 gl-align-self-center"
|
||||
:issuable-type="issuable.type"
|
||||
:workspace-type="workspaceType"
|
||||
/>
|
||||
<p
|
||||
class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0"
|
||||
class="gl-font-weight-bold gl-overflow-hidden gl-whitespace-nowrap gl-text-overflow-ellipsis gl-my-0"
|
||||
:title="issuable.title"
|
||||
>
|
||||
{{ issuable.title }}
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ export default {
|
|||
:avatar-size="16"
|
||||
badge-tooltip-prop="name"
|
||||
:badge-sr-only-text="assigneesCollapsedTooltip"
|
||||
class="gl-white-space-nowrap gl-mr-3"
|
||||
class="gl-whitespace-nowrap gl-mr-3"
|
||||
>
|
||||
<template #avatar="{ avatar }">
|
||||
<gl-avatar-link v-gl-tooltip :href="avatar.webUrl" :title="avatar.name">
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ export default {
|
|||
<template v-else-if="hasParent">
|
||||
<gl-link
|
||||
data-testid="work-item-parent-link"
|
||||
class="gl-link gl-text-gray-900 gl-display-inline-block gl-max-w-full gl-white-space-nowrap gl-text-overflow-ellipsis gl-overflow-hidden"
|
||||
class="gl-link gl-text-gray-900 gl-display-inline-block gl-max-w-full gl-whitespace-nowrap gl-text-overflow-ellipsis gl-overflow-hidden"
|
||||
:href="parent.webUrl"
|
||||
>{{ listboxText }}</gl-link
|
||||
>
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class ProjectsFinder < UnionFinder
|
|||
|
||||
public_visibility_levels = Gitlab::VisibilityLevel.levels_for_user(current_user)
|
||||
|
||||
!public_visibility_levels.include?(params[:visibility_level].to_i)
|
||||
public_visibility_levels.exclude?(params[:visibility_level].to_i)
|
||||
end
|
||||
|
||||
def owned_projects?
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ module ApplicationSettingsHelper
|
|||
|
||||
def oauth_providers_checkboxes(form)
|
||||
button_based_providers.map do |source|
|
||||
checked = !@application_setting.disabled_oauth_sign_in_sources.include?(source.to_s)
|
||||
checked = @application_setting.disabled_oauth_sign_in_sources.exclude?(source.to_s)
|
||||
name = Gitlab::Auth::OAuth::Provider.label_for(source)
|
||||
|
||||
form.gitlab_ui_checkbox_component(
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ module Ci
|
|||
|
||||
gl_badge_tag(variant: variant, size: :md, href: path, class: badge_classes, title: title, data: data) do
|
||||
if show_status_text
|
||||
content_tag(:span, ci_icon_for_status(status), { class: icon_wrapper_class }) + content_tag(:span, status.label, { class: 'gl-mx-2 gl-white-space-nowrap', data: { testid: 'ci-icon-text' } })
|
||||
content_tag(:span, ci_icon_for_status(status), { class: icon_wrapper_class }) + content_tag(:span, status.label, { class: 'gl-mx-2 gl-whitespace-nowrap', data: { testid: 'ci-icon-text' } })
|
||||
else
|
||||
content_tag(:span, ci_icon_for_status(status), { class: icon_wrapper_class })
|
||||
end
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ module ProjectsHelper
|
|||
|
||||
def project_allowed_visibility_levels(project)
|
||||
Gitlab::VisibilityLevel.values.select do |level|
|
||||
project.visibility_level_allowed?(level) && !restricted_levels.include?(level)
|
||||
project.visibility_level_allowed?(level) && restricted_levels.exclude?(level)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ module TreeHelper
|
|||
part_path = File.join(part_path, part) unless part_path.empty?
|
||||
part_path = part if part_path.empty?
|
||||
|
||||
next if parts.count > max_links && !parts.last(2).include?(part)
|
||||
next if parts.count > max_links && parts.last(2).exclude?(part)
|
||||
|
||||
yield(part, part_path)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ module Integrations
|
|||
|
||||
failed_jobs = builds.select do |build|
|
||||
# Select jobs which doesn't have a successful retry
|
||||
build[:status] == 'failed' && !succeeded_job_names.include?(build[:name])
|
||||
build[:status] == 'failed' && succeeded_job_names.exclude?(build[:name])
|
||||
end
|
||||
|
||||
failed_jobs.uniq { |job| job[:name] }.reverse
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ module Integrations
|
|||
invalid_attributes = attributes.keys - ATTRIBUTES
|
||||
if invalid_attributes.present?
|
||||
raise ArgumentError, "Invalid attributes #{invalid_attributes.inspect}"
|
||||
elsif !TYPES.include?(self[:type])
|
||||
elsif TYPES.exclude?(self[:type])
|
||||
raise ArgumentError, "Invalid type #{self[:type].inspect}"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ class Label < ApplicationRecord
|
|||
def label_format_reference(format = :id)
|
||||
raise StandardError, 'Unknown format' unless [:id, :name].include?(format)
|
||||
|
||||
if format == :name && !name.include?('"')
|
||||
if format == :name && name.exclude?('"')
|
||||
%("#{name}")
|
||||
else
|
||||
id
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ class MergeRequest < ApplicationRecord
|
|||
def merge_participants
|
||||
participants = [author]
|
||||
|
||||
if auto_merge_enabled? && !participants.include?(merge_user)
|
||||
if auto_merge_enabled? && participants.exclude?(merge_user)
|
||||
participants << merge_user
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ class Milestone < ApplicationRecord
|
|||
raise ArgumentError, _('Cannot refer to a group milestone by an internal id!')
|
||||
end
|
||||
|
||||
if format == :name && !name.include?('"')
|
||||
if format == :name && name.exclude?('"')
|
||||
%("#{name}")
|
||||
else
|
||||
iid
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ class TodoService
|
|||
).distinct_user_ids
|
||||
end
|
||||
|
||||
if users_multiple_todos.present? && !Todo::ACTIONS_MULTIPLE_ALLOWED.include?(attributes.fetch(:action))
|
||||
if users_multiple_todos.present? && Todo::ACTIONS_MULTIPLE_ALLOWED.exclude?(attributes.fetch(:action))
|
||||
excluded_user_ids += pending_todos(
|
||||
users_multiple_todos,
|
||||
attributes.slice(:project_id, :target_id, :target_type, :commit_id, :discussion, :action)
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@
|
|||
.gl-display-flex.gl-py-3
|
||||
.gl-mr-auto.gl-overflow-hidden.gl-text-overflow-ellipsis
|
||||
= link_to project.full_name, admin_project_path(project)
|
||||
%span.gl-white-space-nowrap.gl-text-right
|
||||
%span.gl-whitespace-nowrap.gl-text-right
|
||||
#{time_ago_with_tooltip(project.created_at)}
|
||||
.col-md-4.gl-mb-6
|
||||
= render Pajamas::CardComponent.new do |c|
|
||||
|
|
@ -192,7 +192,7 @@
|
|||
.gl-mr-auto.gl-overflow-hidden.gl-text-overflow-ellipsis
|
||||
= link_to [:admin, user] do
|
||||
= user.name
|
||||
%span.gl-white-space-nowrap.gl-text-right
|
||||
%span.gl-whitespace-nowrap.gl-text-right
|
||||
#{time_ago_with_tooltip(user.created_at)}
|
||||
.col-md-4.gl-mb-6
|
||||
= render Pajamas::CardComponent.new do |c|
|
||||
|
|
@ -203,5 +203,5 @@
|
|||
.gl-mr-auto.gl-overflow-hidden.gl-text-overflow-ellipsis
|
||||
= link_to [:admin, group] do
|
||||
= group.full_name
|
||||
%span.gl-white-space-nowrap.gl-text-right
|
||||
%span.gl-whitespace-nowrap.gl-text-right
|
||||
#{time_ago_with_tooltip(group.created_at)}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
= render_if_exists "dashboard/todos/review_summary", local_assigns: { todo: todo }
|
||||
|
||||
.todo-timestamp.gl-white-space-nowrap.gl-sm-ml-3.gl-mt-2.gl-mb-2.gl-sm-my-0.gl-px-2.gl-sm-px-0
|
||||
.todo-timestamp.gl-whitespace-nowrap.gl-sm-ml-3.gl-mt-2.gl-mb-2.gl-sm-my-0.gl-px-2.gl-sm-px-0
|
||||
%span.todo-timestamp.gl-font-sm.gl-text-secondary
|
||||
= todo_due_date(todo)
|
||||
#{time_ago_with_tooltip(todo.created_at)}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
|
||||
- if current_user
|
||||
- unless has_label
|
||||
%span.gl-float-left.gl-white-space-nowrap= _("Visibility:")
|
||||
%span.gl-float-left.gl-whitespace-nowrap= _("Visibility:")
|
||||
= gl_redirect_listbox_tag(projects_filter_items, selected, class: 'gl-ml-3', data: { placement: 'right' })
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
.tree-ref-holder.gl-mb-3.gl-sm-mb-0.gl-max-w-26
|
||||
#js-blob-ref-switcher{ data: { project_id: @project.id, ref: @ref, ref_type: @ref_type, namespace: "/-/find_file" } }
|
||||
%ul.breadcrumb.repo-breadcrumb.gl-flex-nowrap
|
||||
%li.breadcrumb-item.gl-white-space-nowrap
|
||||
%li.breadcrumb-item.gl-whitespace-nowrap
|
||||
= link_to project_tree_path(@project, @ref, ref_type: @ref_type) do
|
||||
= @project.path
|
||||
%li.file-finder.breadcrumb-item
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
- if label.description.present?
|
||||
.gl-my-1
|
||||
= markdown_field(label, :description)
|
||||
%ul.label-links.gl-m-0.gl-p-0.gl-white-space-nowrap
|
||||
%ul.label-links.gl-m-0.gl-p-0.gl-whitespace-nowrap
|
||||
- if label.lock_on_merge
|
||||
%li.inline.gl-mr-3.gl-mt-1
|
||||
.label-badge.gl-bg-orange-50= _('Lock on merge')
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@
|
|||
= hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil, data: { meta: '' }
|
||||
|
||||
= dropdown_tag(users_dropdown_label(issuable.assignees), options: assignees_dropdown_options(issuable.to_ability_name))
|
||||
= link_to _('Assign to me'), '#', class: "assign-to-me-link gl-white-space-nowrap gl-md-pl-3 #{'hide' if issuable.assignees.include?(current_user)}", data: { testid: 'assign-to-me-link' }
|
||||
= link_to _('Assign to me'), '#', class: "assign-to-me-link gl-whitespace-nowrap gl-md-pl-3 #{'hide' if issuable.assignees.include?(current_user)}", data: { testid: 'assign-to-me-link' }
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
%div
|
||||
.issuable-form-select-holder
|
||||
= f.gitlab_ui_datepicker :start_date, data: { testid: "start-date-field" }, placeholder: _('Select start date'), autocomplete: 'off'
|
||||
%a.gl-white-space-nowrap.gl-pl-4.js-clear-start-date{ href: "#" }= _('Clear start date')
|
||||
%a.gl-whitespace-nowrap.gl-pl-4.js-clear-start-date{ href: "#" }= _('Clear start date')
|
||||
.gl-form-group
|
||||
%div
|
||||
= f.label :due_date, _('Due Date')
|
||||
%div
|
||||
.issuable-form-select-holder
|
||||
= f.gitlab_ui_datepicker :due_date, data: { testid: "due-date-field" }, placeholder: _('Select due date'), autocomplete: 'off'
|
||||
%a.gl-white-space-nowrap.gl-pl-4.js-clear-due-date{ href: "#" }= _('Clear due date')
|
||||
%a.gl-whitespace-nowrap.gl-pl-4.js-clear-due-date{ href: "#" }= _('Clear due date')
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
- c.with_header do
|
||||
.gl-flex-grow-2
|
||||
= title
|
||||
.gl-ml-3.gl-flex-shrink-0.gl-font-weight-bold.gl-white-space-nowrap{ class: milestone_counter_class(primary) }
|
||||
.gl-ml-3.gl-flex-shrink-0.gl-font-weight-bold.gl-whitespace-nowrap{ class: milestone_counter_class(primary) }
|
||||
- if show_counter
|
||||
%span
|
||||
= sprite_icon('issues', css_class: 'gl-vertical-align-text-bottom')
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@
|
|||
.block.reference
|
||||
= clipboard_button(text: milestone_ref, title: s_('MilestoneSidebar|Copy reference'), placement: "left", boundary: 'viewport', class: 'sidebar-collapsed-icon js-dont-change-state')
|
||||
.gl-display-flex.gl-align-items-center.gl-justify-content-space-between.gl-mb-2.hide-collapsed
|
||||
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-white-space-nowrap
|
||||
%span.gl-overflow-hidden.gl-text-overflow-ellipsis.gl-whitespace-nowrap
|
||||
= s_('MilestoneSidebar|Reference:')
|
||||
%span{ title: milestone_ref }
|
||||
= milestone_ref
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
= sprite_icon('issues', size: 14, css_class: 'gl-mr-2')
|
||||
= badge_count(project.open_issues_count)
|
||||
= render_if_exists 'shared/projects/actions', project: project
|
||||
.updated-note.gl-font-sm.gl-white-space-nowrap.gl-justify-content-end
|
||||
.updated-note.gl-font-sm.gl-whitespace-nowrap.gl-justify-content-end
|
||||
%span
|
||||
= _('Updated')
|
||||
= updated_tooltip
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
= render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path
|
||||
|
||||
= render_if_exists 'shared/projects/badges', project: project
|
||||
.updated-note.gl-font-sm.gl-white-space-nowrap.gl-justify-content-start
|
||||
.updated-note.gl-font-sm.gl-whitespace-nowrap.gl-justify-content-start
|
||||
%span
|
||||
= _('Updated')
|
||||
= updated_tooltip
|
||||
|
|
|
|||
|
|
@ -34,4 +34,4 @@
|
|||
= snippet_file_count(snippet)
|
||||
%span.has-tooltip{ title: visibility_level_label(snippet.visibility_level), data: { testid: 'snippet-visibility-content', qa_snippet_visibility: visibility_level_label(snippet.visibility_level) } }
|
||||
= visibility_level_icon(snippet.visibility_level)
|
||||
.gl-white-space-nowrap.gl-font-sm.gl-text-secondary= _('updated %{timeAgo}').html_safe % { timeAgo: time_ago_with_tooltip(snippet.updated_at, placement: 'bottom') }
|
||||
.gl-whitespace-nowrap.gl-font-sm.gl-text-secondary= _('updated %{timeAgo}').html_safe % { timeAgo: time_ago_with_tooltip(snippet.updated_at, placement: 'bottom') }
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ module Gitlab
|
|||
|
||||
LOOSE_APP_ASSETS = lambda do |logical_path, filename|
|
||||
filename.start_with?(*asset_roots) &&
|
||||
!['.js', '.css', '.md', '.vue', '.graphql', ''].include?(File.extname(logical_path))
|
||||
['.js', '.css', '.md', '.vue', '.graphql', ''].exclude?(File.extname(logical_path))
|
||||
end
|
||||
|
||||
app.config.assets.precompile << LOOSE_APP_ASSETS
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
- build_artifacts
|
||||
- capacity_planning
|
||||
- cell
|
||||
- ci_scaling
|
||||
- cloud_connector
|
||||
- cloud_native_installation
|
||||
- code_quality
|
||||
|
|
|
|||
|
|
@ -1059,7 +1059,7 @@ Gitlab.ee do
|
|||
Settings.kerberos['https'] = Settings.gitlab.https if Settings.kerberos['https'].nil?
|
||||
Settings.kerberos['port'] ||= Settings.kerberos.https ? 8443 : 8088
|
||||
|
||||
if Settings.kerberos['enabled'] && !Settings.omniauth.providers.map(&:name).include?('kerberos')
|
||||
if Settings.kerberos['enabled'] && Settings.omniauth.providers.map(&:name).exclude?('kerberos')
|
||||
Settings.omniauth.providers << GitlabSettings::Options.build({ 'name' => 'kerberos' })
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveCreateEmptyEmbeddingsRecordsWorker < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.0'
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# This is to clean up the cron schedule for Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker
|
||||
# which was removed in
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/438337
|
||||
# TODO: make shard-aware. See https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/3430
|
||||
Gitlab::SidekiqSharding::Validator.allow_unrouted_sidekiq_calls do
|
||||
removed_job = Sidekiq::Cron::Job.find('llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker')
|
||||
removed_job.destroy if removed_job
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# This is to remove the cron schedule for a deleted job, so there is no
|
||||
# meaningful way to reverse it.
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
bc9dbe0d22d8988934d2b8af1c89295bb190e6995278b8864f327ba3fba84ae5
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation for the Code Intelligence feature."
|
||||
---
|
||||
|
||||
# Code intelligence development guidelines
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation for extending the merge request report widget with additional features."
|
||||
---
|
||||
|
||||
# Merge request widget extensions
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation explaining the design and workflow of merge request approval rules."
|
||||
---
|
||||
|
||||
# Approval rules development guidelines
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation for the backend design and flow of merge request diffs."
|
||||
---
|
||||
|
||||
# Merge request diffs development guide
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation explaining how the different parts of the Vue-based frontend diffs are generated."
|
||||
---
|
||||
|
||||
# Merge request diffs frontend overview
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer documentation for how diffs are generated and rendered in GitLab."
|
||||
---
|
||||
|
||||
# Working with diffs
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Code Review
|
||||
info: "See the Technical Writers assigned to Development Guidelines: https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines"
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer information explaining terminology and features used in merge requests."
|
||||
---
|
||||
|
||||
# Merge request concepts
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Code Review
|
||||
info: Detailing the process to add a new mergeability check
|
||||
info: Any user with at least the Maintainer role can merge updates to this content. For details, see https://docs.gitlab.com/ee/development/development_processes.html#development-guidelines-review.
|
||||
description: "Developer information explaining the process to add a new mergeability check"
|
||||
---
|
||||
|
||||
# Mergeability framework
|
||||
|
|
|
|||
|
|
@ -38,17 +38,9 @@ Like default roles, custom roles are [inherited](../../user/project/members/inde
|
|||
- A custom role can enable additional abilities for a `base_access_level` but it cannot disable a permission. As a result, custom roles are "additive only". The rationale for this choice is [in this comment](https://gitlab.com/gitlab-org/gitlab/-/issues/352891#note_1059561579).
|
||||
- Custom role abilities are supported at project level and group level.
|
||||
|
||||
## How to implement a new ability for custom roles
|
||||
## Refactoring abilities
|
||||
|
||||
Usually 2-3 merge requests should be created for a new ability. The rough guidance is following:
|
||||
|
||||
1. Pick a feature you want to add abilities to custom roles.
|
||||
1. Refactor & consolidate abilities for the feature (1-2 merge requests depending on the feature complexity)
|
||||
1. Implement a new ability (1 merge request)
|
||||
|
||||
### Refactoring abilities
|
||||
|
||||
#### Finding existing abilities checks
|
||||
### Finding existing abilities checks
|
||||
|
||||
Abilities are often [checked in multiple locations](../permissions/authorizations.md#where-should-permissions-be-checked) for a single endpoint or web request. Therefore, it can be difficult to find the list of authorization checks that are run for a given endpoint.
|
||||
|
||||
|
|
@ -75,7 +67,7 @@ POLICY CHECK DEBUG -> policy: GlobalPolicy, ability: create_group, called_from:
|
|||
Use this setting to learn more about authorization checks while
|
||||
refactoring. You should not keep this setting enabled for any specs on the default branch.
|
||||
|
||||
#### Understanding logic for individual abilities
|
||||
### Understanding logic for individual abilities
|
||||
|
||||
References to an ability may appear in a `DeclarativePolicy` class many times
|
||||
and depend on conditions and rules which reference other abilities. As a result,
|
||||
|
|
@ -147,7 +139,7 @@ policy.debug(:read_group)
|
|||
@prevented=true>
|
||||
```
|
||||
|
||||
#### Abilities consolidation
|
||||
### Abilities consolidation
|
||||
|
||||
Every feature added to custom roles should have minimal abilities. For most features, having `read_*` and `admin_*` should be enough. You should consolidate all:
|
||||
|
||||
|
|
@ -173,9 +165,12 @@ the parent group will allow the custom role to access the group security dashboa
|
|||
for each project in that group. Enabling the same permission on a specific project will allow access to that projects'
|
||||
security dashboard.
|
||||
|
||||
### Implement a new ability
|
||||
## How to add support for an ability to custom roles
|
||||
|
||||
#### Step 1. Generate a configuration file
|
||||
If adding an existing ability, consider [refactoring & consolidating abilities for the feature](#refactoring-abilities)
|
||||
before in a separate merge request, before completing the below.
|
||||
|
||||
### Step 1. Generate a configuration file
|
||||
|
||||
- Run `./ee/bin/custom-ability <ABILITY_NAME>` to generate a configuration file for the new ability.
|
||||
- This will generate a YAML file in `ee/config/custom_abilities` which follows the following schema:
|
||||
|
|
@ -191,13 +186,13 @@ security dashboard.
|
|||
| `group_ability` | yes | Boolean value to indicate whether this ability is checked on group level. |
|
||||
| `project_ability` | yes | Boolean value to whether this ability is checked on project level. |
|
||||
| `requirements` | no | The list of custom permissions this ability is dependent on. For instance `admin_vulnerability` is dependent on `read_vulnerability`. If none, then enter `[]` |
|
||||
| `available_from_access_level` | no | The access level from which this ability is available, if applicable. See the section on [understanding logic for individual abilities](#understanding-logic-for-individual-abilities) for help on determining the base access level for an ability. |
|
||||
| `available_from_access_level` | no | The access level of the predefined role from which this ability is available, if applicable. See the section on [understanding logic for individual abilities](#understanding-logic-for-individual-abilities) for help on determining the base access level for an ability. This is for information only and has no impact on how custom roles operate. |
|
||||
|
||||
#### Step 2: Create a spec file and update validation schema
|
||||
### Step 2: Create a spec file and update validation schema
|
||||
|
||||
- Run `bundle exec rails generate gitlab:custom_roles:code --ability <ABILITY_NAME>` which will update the permissions validation schema file and create an empty spec file.
|
||||
|
||||
#### Step 3: Update policies
|
||||
### Step 3: Update policies
|
||||
|
||||
- If the ability is checked on a group level, add rule(s) to GroupPolicy to enable the ability.
|
||||
- For example: if the ability we would like to add is `read_dependency`, then an update to `ee/app/policies/ee/group_policy.rb` would look like as follows:
|
||||
|
|
@ -237,7 +232,7 @@ end
|
|||
|
||||
- Not all abilities need to be enabled on both levels, for instance `admin_terraform_state` allows users to manage a project's terraform state. It only needs to be enabled on the project level and not the group level, and thus only needs to be configured in `ee/app/policies/ee/project_policy.rb`.
|
||||
|
||||
#### Step 4: Verify
|
||||
### Step 4: Verify
|
||||
|
||||
- Ensure SaaS mode is enabled with `GITLAB_SIMULATE_SAAS=1`.
|
||||
- Go to any Group that you are an owner of, then go to `Settings -> Roles and Permissions`.
|
||||
|
|
@ -245,7 +240,7 @@ end
|
|||
- Go to the Group's `Manage -> Members` page and assign a member to this newly created custom role.
|
||||
- Next, log-in as that member and ensure that you are able to access the page that the custom ability is intended for.
|
||||
|
||||
#### Step 5: Add specs
|
||||
### Step 5: Add specs
|
||||
|
||||
- Add the ability as a trait in the `MemberRoles` factory, `ee/spec/factories/member_roles.rb`.
|
||||
- Add tests to `ee/spec/requests/custom_roles/<ABILITY_NAME>/request_spec.rb` to ensure that once the user has been assigned the custom ability, they can successfully access the controllers, REST API endpoints and GraphQL API endpoints.
|
||||
|
|
@ -311,7 +306,7 @@ end
|
|||
end
|
||||
```
|
||||
|
||||
#### Step 6: Update documentation
|
||||
### Step 6: Update documentation
|
||||
|
||||
- Update the list of custom abilities by running `bundle exec rake gitlab:custom_roles:compile_docs`
|
||||
- Update the GraphQL documentation by running `bundle exec rake gitlab:graphql:compile_docs`
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Use AI-assisted features for relevant information about a merge request."
|
||||
---
|
||||
|
||||
# GitLab Duo in merge requests
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "When you fork a merge request, you can set whether or not members of the upstream repository can contribute to your fork."
|
||||
---
|
||||
|
||||
# Collaborate on merge requests across forks
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "The most common merge request flows in GitLab use forks, protected branches, or both."
|
||||
---
|
||||
|
||||
# Merge request workflows
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Understand how to read the changes proposed in a merge request."
|
||||
---
|
||||
|
||||
# Changes in merge requests
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Understand how to read the display of commits in a merge request."
|
||||
---
|
||||
|
||||
# Merge request commits
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "How to create a merge request for a confidential issue without leaking information publicly."
|
||||
---
|
||||
|
||||
# Merge requests for confidential issues
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Set a merge request dependency to control the merge order of merge requests with related or dependent content."
|
||||
---
|
||||
|
||||
# Merge request dependencies
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Prevent an incomplete merge request from merging until it's ready by setting it as a draft."
|
||||
---
|
||||
|
||||
# Draft merge requests
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Troubleshooting help for merge requests."
|
||||
---
|
||||
|
||||
# Merge request troubleshooting
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Use diff versions to compare pushes contained in a single merge request."
|
||||
---
|
||||
|
||||
# Merge request diff versions
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
stage: Create
|
||||
group: Code Review
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: "Merge requests show the results of CI/CD pipelines and mergeability tests in a reports area."
|
||||
---
|
||||
|
||||
# Merge request widgets
|
||||
|
|
|
|||
|
|
@ -31851,6 +31851,9 @@ msgstr ""
|
|||
msgid "Members|Membership"
|
||||
msgstr ""
|
||||
|
||||
msgid "Members|Pending invitations"
|
||||
msgstr ""
|
||||
|
||||
msgid "Members|Private group information is only accessible to its members."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ RSpec.describe 'Groups > Members > Tabs', :js, feature_category: :groups_and_pro
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'active "Invited" tab' do
|
||||
it 'displays "Invited" tab' do
|
||||
expect(page).to have_selector('.nav-link.active', text: 'Invited')
|
||||
shared_examples 'active "Pending invitations" tab' do
|
||||
it 'displays "Pending invitations" tab' do
|
||||
expect(page).to have_selector('.nav-link.active', text: 'Pending invitations')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -34,10 +34,10 @@ RSpec.describe 'Groups > Members > Tabs', :js, feature_category: :groups_and_pro
|
|||
end
|
||||
|
||||
where(:tab, :count) do
|
||||
'Members' | 3
|
||||
'Invited' | 2
|
||||
'Groups' | 2
|
||||
'Access requests' | 2
|
||||
'Members' | 3
|
||||
'Pending invitations' | 2
|
||||
'Groups' | 2
|
||||
'Access requests' | 2
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
|
@ -56,11 +56,11 @@ RSpec.describe 'Groups > Members > Tabs', :js, feature_category: :groups_and_pro
|
|||
it_behaves_like 'active "Members" tab'
|
||||
end
|
||||
|
||||
context 'when searching "Invited"' do
|
||||
context 'when searching "Pending invitations"' do
|
||||
before do
|
||||
visit group_group_members_path(group)
|
||||
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
within_testid('members-filtered-search-bar') do
|
||||
find_field('Search invited').click
|
||||
|
|
@ -69,7 +69,7 @@ RSpec.describe 'Groups > Members > Tabs', :js, feature_category: :groups_and_pro
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'active "Invited" tab'
|
||||
it_behaves_like 'active "Pending invitations" tab'
|
||||
|
||||
context 'and then searching "Members"' do
|
||||
before do
|
||||
|
|
@ -86,18 +86,18 @@ RSpec.describe 'Groups > Members > Tabs', :js, feature_category: :groups_and_pro
|
|||
end
|
||||
end
|
||||
|
||||
context 'when using "Invited" pagination' do
|
||||
context 'when using "Pending invitations" pagination' do
|
||||
before do
|
||||
visit group_group_members_path(group)
|
||||
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
page.within '.pagination' do
|
||||
click_link '2'
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'active "Invited" tab'
|
||||
it_behaves_like 'active "Pending invitations" tab'
|
||||
|
||||
context 'and then using "Members" pagination' do
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ RSpec.describe 'Projects members', :js, feature_category: :groups_and_projects d
|
|||
end
|
||||
|
||||
it 'shows the project invitee' do
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
expect(members_table).to have_content('test1@abc.com')
|
||||
expect(members_table).not_to have_content('test2@abc.com')
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ RSpec.describe 'Projects > Members > Tabs', :js, feature_category: :groups_and_p
|
|||
|
||||
context 'tabs' do
|
||||
where(:tab, :count) do
|
||||
'Members' | 3
|
||||
'Invited' | 2
|
||||
'Groups' | 2
|
||||
'Access requests' | 2
|
||||
'Members' | 3
|
||||
'Pending invitations' | 2
|
||||
'Groups' | 2
|
||||
'Access requests' | 2
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ describe('MembersTabs', () => {
|
|||
|
||||
expect(tabs[0].text()).toBe('Members 10');
|
||||
expect(tabs[1].text()).toBe('Groups 10');
|
||||
expect(tabs[2].text()).toBe('Invited 10');
|
||||
expect(tabs[2].text()).toBe('Pending invitations 10');
|
||||
expect(tabs[3].text()).toBe('Access requests 10');
|
||||
expect(findActiveTab().text()).toContain('Members');
|
||||
});
|
||||
|
|
@ -149,7 +149,7 @@ describe('MembersTabs', () => {
|
|||
|
||||
expect(findTabByText('Members')).not.toBeUndefined();
|
||||
expect(findTabByText('Groups')).toBeUndefined();
|
||||
expect(findTabByText('Invited')).toBeUndefined();
|
||||
expect(findTabByText('Pending invitations')).toBeUndefined();
|
||||
expect(findTabByText('Access requests')).toBeUndefined();
|
||||
});
|
||||
|
||||
|
|
@ -179,14 +179,14 @@ describe('MembersTabs', () => {
|
|||
});
|
||||
|
||||
describe('when `canManageMembers` is `false`', () => {
|
||||
it('shows all tabs except `Invited` and `Access requests`', async () => {
|
||||
it('shows all tabs except `Pending invitations` and `Access requests`', async () => {
|
||||
await createComponent({
|
||||
provide: { canManageMembers: false, canManageAccessRequests: false },
|
||||
});
|
||||
|
||||
expect(findTabByText('Members')).not.toBeUndefined();
|
||||
expect(findTabByText('Groups')).not.toBeUndefined();
|
||||
expect(findTabByText('Invited')).toBeUndefined();
|
||||
expect(findTabByText('Pending invitations')).toBeUndefined();
|
||||
expect(findTabByText('Access requests')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe RemoveCreateEmptyEmbeddingsRecordsWorker, :migration, feature_category: :scalability do
|
||||
let(:hash_name) { 'cron_job:llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker' }
|
||||
let(:zset_name) { 'cron_job:llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker:enqueued' }
|
||||
let(:job_message) do
|
||||
{ "retry" => 3,
|
||||
"queue" => "default",
|
||||
"version" => 0,
|
||||
"queue_namespace" => "cronjob",
|
||||
"class" => "Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker",
|
||||
"args" => [] }
|
||||
end
|
||||
|
||||
let(:cron_args) do
|
||||
[
|
||||
"symbolize_args", "0", "date_as_argument", "false",
|
||||
"name", "llm_embedding_gitlab_documentation_create_empty_embeddings_records_worker",
|
||||
"queue_name_prefix", "",
|
||||
"cron", "0 5 * * 1,2,3,4,5",
|
||||
"last_enqueue_time", "2024-04-30,05:00:01,+0000",
|
||||
"status", "enabled",
|
||||
"klass", "Llm::Embedding::GitlabDocumentation::CreateEmptyEmbeddingsRecordsWorker",
|
||||
"message", Sidekiq.dump_json(job_message)
|
||||
]
|
||||
end
|
||||
|
||||
context 'when cron job exists' do
|
||||
before do
|
||||
Gitlab::Redis::Queues.with do |redis|
|
||||
redis.hset(hash_name, *cron_args)
|
||||
redis.zadd(zset_name, 1714626000, "2024-05-02T05:00:00Z")
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Gitlab::Redis::Queues.with(&:flushdb)
|
||||
end
|
||||
|
||||
it "deletes the cron job and enqueued jobs" do
|
||||
migrate!
|
||||
|
||||
Gitlab::Redis::Queues.with do |redis|
|
||||
expect(redis.exists(hash_name)).to eq(0)
|
||||
expect(redis.exists(zset_name)).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when cron job does not exist' do
|
||||
it "no-ops" do
|
||||
expect { migrate! }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -44,7 +44,7 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
|
|||
|
||||
invite_member('test@example.com', role: 'Reporter')
|
||||
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
page.within find_invited_member_row('test@example.com') do
|
||||
expect(page).to have_button('Reporter')
|
||||
|
|
@ -68,7 +68,7 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
|
|||
expect(page).to have_button('Reporter')
|
||||
end
|
||||
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
page.within find_invited_member_row('test@example.com') do
|
||||
expect(page).to have_button('Reporter')
|
||||
|
|
@ -107,7 +107,7 @@ RSpec.shared_examples 'inviting members' do |snowplow_invite_label|
|
|||
|
||||
page.refresh
|
||||
|
||||
click_link 'Invited'
|
||||
click_link 'Pending invitations'
|
||||
|
||||
page.within find_invited_member_row(email) do
|
||||
expect(page).to have_button('Reporter')
|
||||
|
|
|
|||
Loading…
Reference in New Issue