Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-06-27 15:24:49 +00:00
parent b9f4411b1b
commit cbb6a29694
128 changed files with 1185 additions and 713 deletions

View File

@ -76,7 +76,7 @@ workflow:
# they serve no purpose and will run anyway when the changes are merged.
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^release-tools\/\d+\.\d+\.\d+-rc\d+$/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/ && $CI_PROJECT_PATH == "gitlab-org/gitlab"'
when: never
- if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby3_1/'
- if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby3_1/ || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^[\d-]+-stable(-ee)?$/'
variables:
<<: [*default-ruby-variables, *default-merge-request-variables]
PIPELINE_NAME: 'Ruby $RUBY_VERSION MR'

View File

@ -220,7 +220,7 @@
{"name":"gitlab-glfm-markdown","version":"0.0.17","platform":"ruby","checksum":"f379545fc53a71c31525025fdb422f46081133af5cced3130ce680b155c2aa69"},
{"name":"gitlab-glfm-markdown","version":"0.0.17","platform":"x86_64-darwin","checksum":"50e0f4865ef7c455426c7c058fc10ff9c8366482d48a63d6f6693b38c4a49c1c"},
{"name":"gitlab-glfm-markdown","version":"0.0.17","platform":"x86_64-linux","checksum":"cc877ff8ceb3aa8a331fdb8991592e35897823e0f77ba9e4b2b65082c665089b"},
{"name":"gitlab-labkit","version":"0.36.0","platform":"ruby","checksum":"35f21d1c3870ed0c9b8321e25d0b0b0b5021805a5d0525d1eb0fde6b103af981"},
{"name":"gitlab-labkit","version":"0.36.1","platform":"ruby","checksum":"04fb6941b7e5fc1fdcee8f9971fa2086a4dc442e39e67a74b992403dd580c300"},
{"name":"gitlab-license","version":"2.5.0","platform":"ruby","checksum":"4c166c469c2ad17876ca43188a4ccebe3feb0726c4c1770047f8dcef96573f4d"},
{"name":"gitlab-mail_room","version":"0.0.25","platform":"ruby","checksum":"223ce7c3c0797b6015eaa37147884e6ddc7be9a7ee90a424358c96bc18613b1a"},
{"name":"gitlab-markup","version":"1.9.0","platform":"ruby","checksum":"7eda045a08ec2d110084252fa13a8c9eac8bdac0e302035ca7db4b82bcbd7ed4"},

View File

@ -706,7 +706,7 @@ GEM
mime-types
gitlab-glfm-markdown (0.0.17)
rb_sys (= 0.9.94)
gitlab-labkit (0.36.0)
gitlab-labkit (0.36.1)
actionpack (>= 5.0.0, < 8.0.0)
activesupport (>= 5.0.0, < 8.0.0)
grpc (>= 1.62)

View File

@ -40,7 +40,7 @@ export default {
<gl-collapsible-listbox
v-model="selected"
:items="databases"
placement="right"
placement="bottom-end"
:toggle-text="selectedDatabase"
toggle-aria-labelled-by="label"
@select="selectDatabase"

View File

@ -206,7 +206,7 @@ export default {
<template>
<gl-disclosure-dropdown
ref="submitDropdown"
placement="right"
placement="bottom-end"
class="submit-review-dropdown"
:class="{ 'submit-review-dropdown-animated': shouldAnimateReviewButton }"
data-testid="submit-review-dropdown"

View File

@ -116,7 +116,7 @@ export default {
:toggle-text="$options.i18n.toggleText"
icon="ellipsis_v"
category="tertiary"
placement="right"
placement="bottom-end"
data-testid="branch-more-actions"
text-sr-only
no-caret

View File

@ -114,7 +114,7 @@ export default {
icon="ellipsis_v"
category="tertiary"
no-caret
placement="right"
placement="bottom-end"
class="gl-hidden md:!gl-block"
:items="dropdownItems"
/>

View File

@ -157,7 +157,7 @@ export default {
text-sr-only
icon="ellipsis_v"
category="tertiary"
placement="right"
placement="bottom-end"
class="note-action-button more-actions-toggle"
no-caret
>

View File

@ -96,7 +96,7 @@ export default {
v-else-if="isManualJob"
icon="retry"
category="primary"
placement="right"
placement="bottom-end"
positioning-strategy="fixed"
variant="confirm"
:items="dropdownItems"

View File

@ -135,7 +135,7 @@ export default {
:aria-label="$options.i18n.downloadArtifacts"
:items="items"
icon="download"
placement="right"
placement="bottom-end"
text-sr-only
data-testid="pipeline-multi-actions-dropdown"
@shown="onDisclosureDropdownShown"

View File

@ -65,7 +65,7 @@ export default {
:toggle-text="$options.i18n.artifacts"
:aria-label="$options.i18n.artifacts"
icon="download"
placement="right"
placement="bottom-end"
text-sr-only
:items="items"
data-testid="artifacts-dropdown"

View File

@ -106,7 +106,7 @@ export default {
v-if="actionItems.length"
category="primary"
variant="confirm"
placement="right"
placement="bottom-end"
:toggle-text="defaultActionText"
:items="actionItems"
:disabled="!canAddCluster"

View File

@ -84,7 +84,7 @@ export default {
icon="ellipsis_v"
no-caret
text-sr-only
placement="right"
placement="bottom-end"
:toggle-text="__('Comment template actions')"
:loading="isDeleting"
category="tertiary"

View File

@ -70,7 +70,7 @@ export default {
}));
},
placement() {
return this.right ? 'right' : 'left';
return this.right ? 'bottom-end' : 'bottom-start';
},
newCustomEmoji() {
return {

View File

@ -824,7 +824,7 @@ export default {
no-caret
icon="ellipsis_v"
category="secondary"
placement="right"
placement="bottom-end"
:toggle-text="__('More actions')"
>
<rollback-component

View File

@ -372,7 +372,7 @@ export default {
block
:toggle-text="__('Options')"
toggle-class="md:gl-hidden"
placement="right"
placement="bottom-end"
:disabled="issueUpdateInProgress"
:items="dropdownItems"
/>

View File

@ -292,6 +292,7 @@ export const resolvers = {
healthStatus,
isGroup,
fullPath,
workItemType,
assignees,
color,
title,
@ -301,9 +302,10 @@ export const resolvers = {
const query = isGroup ? groupWorkItemByIidQuery : workItemByIidQuery;
const variables = {
fullPath: newWorkItemFullPath(fullPath),
fullPath: newWorkItemFullPath(fullPath, workItemType),
iid: NEW_WORK_ITEM_IID,
};
cache.updateQuery({ query, variables }, (sourceData) =>
produce(sourceData, (draftData) => {
if (healthStatus) {

View File

@ -29,7 +29,7 @@ export default {
</script>
<template>
<gl-badge v-gl-tooltip :title="title" variant="warning">
<gl-badge v-gl-tooltip :title="title" variant="warning" class="gl-shrink-0">
<gl-icon name="spam" />
<span class="gl-sr-only">{{ __('Hidden') }}</span>
</gl-badge>

View File

@ -32,7 +32,13 @@ export default {
</script>
<template>
<gl-badge v-gl-tooltip :title="title" variant="warning" data-testid="locked-badge">
<gl-badge
v-gl-tooltip
:title="title"
variant="warning"
data-testid="locked-badge"
class="gl-shrink-0"
>
<gl-icon name="lock" />
<span class="gl-sr-only">{{ __('Locked') }}</span>
</gl-badge>

View File

@ -91,7 +91,11 @@ export default {
</script>
<template>
<gl-badge :variant="badgeProperties.variant" :aria-label="badgeProperties.text">
<gl-badge
:variant="badgeProperties.variant"
:aria-label="badgeProperties.text"
class="gl-shrink-0"
>
<gl-icon :name="badgeProperties.icon" />
{{ badgeProperties.text }}
</gl-badge>

View File

@ -345,7 +345,7 @@ export default {
:auto-close="false"
data-testid="mobile-dropdown"
:loading="isToggleStateButtonLoading"
placement="right"
placement="bottom-end"
>
<template v-if="showMovedSidebarOptions && !glFeatures.notificationsTodosButtons">
<sidebar-subscriptions-widget

View File

@ -96,7 +96,7 @@ export default {
</div>
<gl-disclosure-dropdown
v-if="canUpdateTimelineEvent"
placement="right"
placement="bottom-end"
class="event-note-actions gl-align-self-start"
icon="ellipsis_v"
text-sr-only

View File

@ -81,10 +81,8 @@ export default {
class="issue-sticky-header gl-fixed gl-z-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
data-testid="issue-sticky-header"
>
<div
class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-gap-2 gl-mx-auto"
>
<gl-badge :variant="statusVariant" :icon="statusIcon">
<div class="issue-sticky-header-text gl-flex gl-items-center gl-gap-2 gl-mx-auto">
<gl-badge :variant="statusVariant" :icon="statusIcon" class="gl-shrink-0">
{{ statusText }}
</gl-badge>
<confidentiality-badge

View File

@ -38,7 +38,7 @@ export default {
category="tertiary"
icon="ellipsis_v"
no-caret
placement="right"
placement="bottom-end"
:toggle-text="$options.i18n.taskActions"
text-sr-only
toggle-class="task-list-item-actions gl-opacity-0 gl-p-2! "

View File

@ -45,7 +45,7 @@ export default {
:toggle-text="preferredLocale.text"
:items="locales"
category="tertiary"
placement="right"
placement="bottom-end"
icon="earth"
size="small"
toggle-class="py-0 gl-h-6"

View File

@ -112,7 +112,7 @@ export default {
icon="ellipsis_v"
category="tertiary"
no-caret
placement="right"
placement="bottom-end"
data-testid="user-action-dropdown"
>
<disable-two-factor-dropdown-item

View File

@ -121,7 +121,7 @@ export default {
<div>
<gl-collapsible-listbox
v-if="permissions.canUpdate"
:placement="isDesktop ? 'left' : 'right'"
:placement="isDesktop ? 'bottom-start' : 'bottom-end'"
:header-text="__('Change role')"
:disabled="disabled"
:loading="busy"

View File

@ -65,7 +65,7 @@ export default {
<template>
<div>
<gl-disclosure-dropdown
placement="right"
placement="bottom-end"
category="tertiary"
:aria-label="__('More actions')"
icon="ellipsis_v"

View File

@ -138,7 +138,7 @@ export default {
icon="ellipsis_v"
size="small"
category="tertiary"
placement="right"
placement="bottom-end"
no-caret
:title="__('Thread options')"
:aria-label="__('Thread options')"
@ -179,7 +179,7 @@ export default {
icon="ellipsis_v"
size="small"
category="tertiary"
placement="right"
placement="bottom-end"
no-caret
:title="__('Thread options')"
:aria-label="__('Thread options')"

View File

@ -178,7 +178,7 @@ export default {
data-testid="discussion-preferences-dropdown"
:toggle-text="__('Sort or filter')"
:disabled="isLoading"
placement="right"
placement="bottom-end"
>
<gl-disclosure-dropdown-group id="discussion-sort">
<gl-disclosure-dropdown-item

View File

@ -138,7 +138,7 @@ export default {
:show-select-all-button-label="__('Select all')"
:reset-button-label="__('Deselect all')"
multiple
placement="right"
placement="bottom-end"
@shown="filterListShown"
@hidden="applyFilters"
@reset="deselectAll"

View File

@ -355,7 +355,7 @@ export default {
text-sr-only
icon="ellipsis_v"
category="tertiary"
placement="right"
placement="bottom-end"
class="note-action-button more-actions-toggle"
no-caret
>

View File

@ -199,7 +199,7 @@ export default {
<gl-disclosure-dropdown
category="tertiary"
icon="ellipsis_v"
placement="right"
placement="bottom-end"
:toggle-text="$options.i18n.MORE_ACTIONS_TEXT"
text-sr-only
no-caret

View File

@ -227,7 +227,7 @@ export default {
:text-sr-only="true"
category="tertiary"
no-caret
placement="right"
placement="bottom-end"
:class="{ 'gl-opacity-0 gl-pointer-events-none': disabled }"
data-testid="additional-actions"
:items="items"

View File

@ -162,7 +162,7 @@ export default {
:toggle-text="__('More actions')"
:text-sr-only="true"
category="tertiary"
placement="right"
placement="bottom-end"
no-caret
>
<gl-disclosure-dropdown-item v-gl-modal-directive="$options.confirmClearCacheModal">

View File

@ -1,6 +1,7 @@
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue';
export default {
@ -9,7 +10,7 @@ export default {
GlLink,
GlSprintf,
},
inject: ['terraformHelpPath', 'gitlabHost', 'projectPath'],
inject: ['gitlabHost', 'projectPath'],
props: {
packageName: {
type: String,
@ -38,6 +39,9 @@ export default {
'InfrastructureRegistry|For more information on the Terraform registry, %{linkStart}see our documentation%{linkEnd}.',
),
},
terraformHelpPath: helpPagePath('user/packages/terraform_module_registry/index', {
anchor: 'reference-a-terraform-module',
}),
};
</script>
@ -66,7 +70,7 @@ export default {
/>
<gl-sprintf :message="$options.i18n.helpText">
<template #link="{ content }">
<gl-link :href="terraformHelpPath">{{ content }}</gl-link>
<gl-link :href="$options.terraformHelpPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>

View File

@ -11,11 +11,11 @@ export default () => {
const {
package: packageJson,
canDelete: canDeleteStr,
terraformHelpPath,
gitlabHost,
projectPath,
projectName,
projectListUrl,
svgPath,
} = el.dataset;
const packageEntity = JSON.parse(packageJson);
const canDelete = parseBoolean(canDeleteStr);
@ -34,7 +34,7 @@ export default () => {
projectListUrl,
projectName,
projectPath,
terraformHelpPath,
svgPath,
},
render(createElement) {
return createElement(PackagesApp);

View File

@ -1,10 +1,13 @@
#import "~/packages_and_registries/package_registry/graphql/fragments/package_group_settings.fragment.graphql"
query getGroupPackageSettings($fullPath: ID!) {
project(fullPath: $fullPath) {
query getGroupPackageSettings($fullPath: ID!, $isGroupPage: Boolean = false) {
project(fullPath: $fullPath) @skip(if: $isGroupPage) {
id
group {
...GroupPackageSettings
}
}
group(fullPath: $fullPath) @include(if: $isGroupPage) {
...GroupPackageSettings
}
}

View File

@ -1,5 +1,4 @@
#import "~/packages_and_registries/package_registry/graphql/fragments/package_data.fragment.graphql"
#import "~/packages_and_registries/package_registry/graphql/fragments/package_group_settings.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getPackages(
@ -37,9 +36,6 @@ query getPackages(
...PageInfo
}
}
group {
...GroupPackageSettings
}
}
group(fullPath: $fullPath) @include(if: $isGroupPage) {
id
@ -67,6 +63,5 @@ query getPackages(
...PageInfo
}
}
...GroupPackageSettings
}
}

View File

@ -5,6 +5,7 @@ import { createAlert, VARIANT_INFO } from '~/alert';
import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import { fetchPolicies } from '~/lib/graphql';
import { historyReplaceState } from '~/lib/utils/common_utils';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { s__ } from '~/locale';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants';
import {
@ -15,6 +16,7 @@ import {
PACKAGE_HELP_URL,
} from '~/packages_and_registries/package_registry/constants';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
import getGroupPackageSettings from '~/packages_and_registries/package_registry/graphql/queries/get_group_package_settings.query.graphql';
import DeletePackages from '~/packages_and_registries/package_registry/components/functional/delete_packages.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
@ -41,7 +43,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
inject: ['emptyListIllustration', 'isGroupPage', 'fullPath', 'settingsPath'],
inject: ['emptyListIllustration', 'canDeletePackages', 'isGroupPage', 'fullPath', 'settingsPath'],
data() {
return {
packagesResource: {},
@ -49,6 +51,7 @@ export default {
filters: {},
isDeleteInProgress: false,
pageParams: {},
groupSettings: {},
};
},
apollo: {
@ -65,16 +68,31 @@ export default {
return !this.sort;
},
},
groupSettings: {
query: getGroupPackageSettings,
variables() {
return {
fullPath: this.fullPath,
isGroupPage: this.isGroupPage,
};
},
update(data) {
return this.isGroupPage
? data[this.graphqlResource].packageSettings ?? {}
: data[this.graphqlResource].group?.packageSettings ?? {};
},
skip() {
return !(this.packagesCount > 0 && this.canDeletePackages);
},
error(error) {
Sentry.captureException(error);
},
},
},
computed: {
packages() {
return this.packagesResource?.packages ?? {};
},
groupSettings() {
return this.isGroupPage
? this.packagesResource?.packageSettings ?? {}
: this.packagesResource?.group?.packageSettings ?? {};
},
queryVariables() {
return {
isGroupPage: this.isGroupPage,

View File

@ -50,7 +50,7 @@ export default {
<gl-disclosure-dropdown
:toggle-text="$options.i18n.QUICK_START"
variant="confirm"
placement="right"
placement="bottom-end"
@shown="track('click_dropdown')"
>
<div class="gl-px-3 gl-py-2">

View File

@ -169,7 +169,7 @@ export default {
v-model="sortOrder"
:toggle-text="$options.sortOrderOptions[sortOrder].text"
:items="Object.values($options.sortOrderOptions)"
placement="right"
placement="bottom-end"
data-testid="performance-bar-sort-order"
/>
</div>

View File

@ -98,7 +98,7 @@ export default {
<gl-button-group>
<gl-collapsible-listbox
v-model="selectedSortOptionTitle"
placement="right"
placement="bottom-end"
class="gl-z-1"
toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
:toggle-text="selectedSortOptionTitle"

View File

@ -303,7 +303,7 @@ export default {
<gl-disclosure-dropdown
data-testid="snippets-more-actions-dropdown"
placement="right"
placement="bottom-end"
block
@shown="onShowDropdown"
@hidden="onHideDropdown"

View File

@ -66,7 +66,7 @@ export default {
v-model="selectedKey"
data-testid="tags-dropdown"
:items="sortOptionsListboxItems"
placement="right"
placement="bottom-end"
:toggle-text="selectedSortMethod"
@select="visitUrlFromOption"
/>

View File

@ -62,7 +62,7 @@ export default {
<gl-collapsible-listbox
:items="filteredChanges"
size="small"
placement="right"
placement="bottom-end"
searchable
@search="search"
>

View File

@ -31,7 +31,7 @@ export default {
<template>
<div>
<gl-disclosure-dropdown
placement="right"
placement="bottom-end"
toggle-text="Use an existing commit message"
category="tertiary"
:items="dropdownItems"

View File

@ -91,7 +91,7 @@ export default {
icon="ellipsis_v"
no-caret
category="tertiary"
placement="right"
placement="bottom-end"
text-sr-only
size="small"
toggle-class="gl-p-2!"

View File

@ -110,7 +110,7 @@ export default {
<gl-collapsible-listbox
ref="dropdown"
v-model="alertStatus"
placement="right"
placement="bottom-end"
:header-text="headerText"
:items="items"
block

View File

@ -140,7 +140,7 @@ export default {
:toggle-text="$options.i18n.defaultLabel"
category="primary"
variant="confirm"
placement="right"
placement="bottom-end"
class="code-dropdown gl-text-left"
fluid-width
data-testid="code-dropdown"

View File

@ -67,7 +67,7 @@ export default {
<gl-disclosure-dropdown
category="primary"
variant="confirm"
placement="right"
placement="bottom-end"
block
:toggle-text="$options.labels.defaultLabel"
>

View File

@ -40,7 +40,7 @@ export default {
</script>
<template>
<gl-badge v-gl-tooltip :title="confidentialTooltip" variant="warning">
<gl-badge v-gl-tooltip :title="confidentialTooltip" variant="warning" class="gl-shrink-0">
<gl-icon name="eye-slash" :size="16" />
<span data-testid="confidential-badge-text" :class="confidentialTextClass">{{
__('Confidential')

View File

@ -85,7 +85,7 @@ export default {
:toggle-text="$options.i18n.defaultLabel"
:title="$options.i18n.defaultLabel"
category="secondary"
placement="right"
placement="bottom-end"
icon="download"
text-sr-only
fluid-width

View File

@ -48,7 +48,7 @@ export default {
<span v-if="textOnly" v-gl-tooltip="title">
{{ __('Imported') }}
</span>
<gl-badge v-else v-gl-tooltip="title">
<gl-badge v-else v-gl-tooltip="title" class="gl-shrink-0">
{{ __('Imported') }}
</gl-badge>
</template>

View File

@ -46,7 +46,7 @@ export default {
no-caret
:toggle-text="$options.i18n.actions"
text-sr-only
placement="right"
placement="bottom-end"
category="tertiary"
/>
</template>

View File

@ -62,7 +62,7 @@ export default {
<gl-disclosure-dropdown
data-testid="apply-suggestion-dropdown"
fluid-width
placement="right"
placement="bottom-end"
size="small"
:disabled="disabled"
:toggle-text="dropdownText"

View File

@ -229,7 +229,7 @@ export default {
v-gl-tooltip="showDropdownTooltip"
:title="$options.i18n.mergeRequestActions"
data-testid="dropdown-toggle"
placement="right"
placement="bottom-end"
block
class="gl-w-full"
:auto-close="false"

View File

@ -0,0 +1,21 @@
import SettingsSection from './settings_section.vue';
export default {
component: SettingsSection,
title: 'vue_shared/settings/settings_section',
};
const Template = (args, { argTypes }) => ({
components: { SettingsSection },
props: Object.keys(argTypes),
template: `
<settings-section v-bind="$props" heading="Settings section heading">
<template #description>Settings section description</template>
<template #default>
<p>Settings section content</p>
</template>
</settings-section>
`,
});
export const Default = Template.bind({});

View File

@ -0,0 +1,35 @@
<script>
export default {
props: {
heading: {
type: String,
required: true,
},
description: {
type: String,
required: false,
default: null,
},
},
};
</script>
<template>
<section class="settings-section">
<div class="settings-sticky-header">
<div class="settings-sticky-header-inner">
<h2 class="gl-heading-2 !gl-mb-2">
<slot v-if="$scopedSlots.heading" name="heading"></slot>
<template v-else>{{ heading }}</template>
</h2>
<p v-if="$scopedSlots.description || description" class="gl-text-secondary gl-m-0">
<slot v-if="$scopedSlots.description" name="description"></slot>
<template v-else>{{ description }}</template>
</p>
</div>
</div>
<div>
<slot></slot>
</div>
</section>
</template>

View File

@ -55,6 +55,6 @@ export default {
:loading="loading"
icon="download"
size="small"
placement="right"
placement="bottom-end"
/>
</template>

View File

@ -14,7 +14,7 @@ import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { fetchPolicies } from '~/lib/graphql';
import { setNewWorkItemCache } from '~/work_items/graphql/cache_utils';
import { findWidget } from '~/issues/list/utils';
import { newWorkItemFullPath, isWorkItemItemValidEnum } from '~/work_items/utils';
import { newWorkItemFullPath } from '~/work_items/utils';
import {
I18N_WORK_ITEM_CREATE_BUTTON_LABEL,
I18N_WORK_ITEM_ERROR_CREATING,
@ -79,7 +79,6 @@ export default {
selectedWorkItemTypeId: null,
loading: false,
showWorkItemTypeSelect: false,
newWorkItemPath: newWorkItemFullPath(this.fullPath),
};
},
apollo: {
@ -94,7 +93,7 @@ export default {
};
},
skip() {
return !this.fullPath;
return !this.fullPath || !this.selectedWorkItemTypeName;
},
update(data) {
return data?.workspace?.workItem ?? {};
@ -119,13 +118,22 @@ export default {
update(data) {
return data.workspace?.workItemTypes?.nodes;
},
result() {
async result() {
if (!this.workItemTypes?.length) {
return;
}
if (this.workItemTypes?.length === 1) {
this.selectedWorkItemTypeId = this.workItemTypes[0].id;
} else {
this.workItemTypes.forEach(async (workItemType) => {
await setNewWorkItemCache(
this.isGroup,
this.fullPath,
workItemType?.widgetDefinitions,
workItemType.name,
workItemType.id,
);
});
this.showWorkItemTypeSelect = true;
}
},
@ -135,6 +143,9 @@ export default {
},
},
computed: {
newWorkItemPath() {
return newWorkItemFullPath(this.fullPath, this.selectedWorkItemTypeName);
},
isLoading() {
return this.$apollo.queries.workItemTypes.loading || this.$apollo.queries.workItem.loading;
},
@ -161,27 +172,28 @@ export default {
selectedWorkItemType() {
return this.workItemTypes?.find((item) => item.id === this.selectedWorkItemTypeId);
},
selectedWorkItemTypeName() {
return this.selectedWorkItemType?.name;
},
formOptions() {
return [{ value: null, text: s__('WorkItem|Select type') }, ...this.workItemTypesForSelect];
},
createErrorText() {
const workItemType = this.selectedWorkItemType?.name;
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, workItemType);
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, this.selectedWorkItemTypeName);
},
createWorkItemText() {
const workItemType = this.selectedWorkItemType?.name;
return sprintfWorkItem(I18N_WORK_ITEM_CREATE_BUTTON_LABEL, workItemType);
return sprintfWorkItem(I18N_WORK_ITEM_CREATE_BUTTON_LABEL, this.selectedWorkItemTypeName);
},
makeConfidentialText() {
return sprintfWorkItem(
s__(
'WorkItem|This %{workItemType} is confidential and should only be visible to users having at least Reporter access.',
),
this.selectedWorkItemType?.name,
this.selectedWorkItemTypeName,
);
},
titleText() {
return sprintfWorkItem(s__('WorkItem|New %{workItemType}'), this.selectedWorkItemType?.name);
return sprintfWorkItem(s__('WorkItem|New %{workItemType}'), this.selectedWorkItemTypeName);
},
canUpdate() {
return this.workItem?.userPermissions?.updateWorkItem;
@ -228,17 +240,6 @@ export default {
const title = newValue || this.workItemTitle;
this.isTitleValid = Boolean(title.trim());
},
updateCache() {
if (!this.selectedWorkItemTypeId || !isWorkItemItemValidEnum(this.workItemType)) {
return;
}
setNewWorkItemCache(
this.isGroup,
this.fullPath,
this.selectedWorkItemType?.widgetDefinitions,
this.workItemType,
);
},
async updateDraftData(type, value) {
if (type === 'title') {
this.validate(value);
@ -251,6 +252,7 @@ export default {
input: {
isGroup: this.isGroup,
fullPath: this.fullPath,
workItemType: this.selectedWorkItemTypeName || this.workItemTypeName,
[type]: value,
},
},
@ -367,98 +369,100 @@ export default {
v-model="selectedWorkItemTypeId"
:options="formOptions"
class="gl-max-w-26"
@change="updateCache"
/>
</gl-form-group>
</div>
<work-item-title
ref="title"
data-testid="title-input"
is-editing
:is-valid="isTitleValid"
:title="workItemTitle"
@updateDraft="updateDraftData('title', $event)"
@updateWorkItem="createWorkItem"
/>
<div data-testid="work-item-overview" class="work-item-overview">
<section>
<work-item-description
edit-mode
:autofocus="false"
:full-path="fullPath"
create-flow
:show-buttons-below-field="false"
:work-item-id="$options.NEW_WORK_ITEM_GID"
:work-item-iid="$options.NEW_WORK_ITEM_IID"
@error="updateError = $event"
@updateDraft="updateDraftData('description', $event)"
/>
<gl-form-group :label="__('Confidentiality')" label-for="work-item-confidential">
<gl-form-checkbox
id="work-item-confidential"
v-model="isConfidential"
data-testid="confidential-checkbox"
@change="updateDraftData('confidential', $event)"
>
{{ makeConfidentialText }}
</gl-form-checkbox>
</gl-form-group>
</section>
<aside
v-if="hasWidgets"
data-testid="work-item-overview-right-sidebar"
class="work-item-overview-right-sidebar"
:class="{ 'is-modal': true }"
>
<template v-if="workItemAssignees">
<work-item-assignees
class="gl-mb-5 js-assignee"
:can-update="canUpdate"
<div v-if="selectedWorkItemTypeId" data-testid="create-work-item">
<work-item-title
ref="title"
data-testid="title-input"
is-editing
:is-valid="isTitleValid"
:title="workItemTitle"
@updateDraft="updateDraftData('title', $event)"
@updateWorkItem="createWorkItem"
/>
<div data-testid="work-item-overview" class="work-item-overview">
<section>
<work-item-description
edit-mode
:autofocus="false"
:full-path="fullPath"
:work-item-id="workItem.id"
:assignees="workItemAssignees.assignees.nodes"
:participants="workItemParticipantNodes"
:work-item-author="workItemAuthor"
:allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees"
:work-item-type="workItemType"
:can-invite-members="workItemAssignees.canInviteMembers"
@error="$emit('error', $event)"
create-flow
:show-buttons-below-field="false"
:work-item-id="$options.NEW_WORK_ITEM_GID"
:work-item-iid="$options.NEW_WORK_ITEM_IID"
:work-item-type-name="selectedWorkItemTypeName"
@error="updateError = $event"
@updateDraft="updateDraftData('description', $event)"
/>
</template>
<template v-if="workItemHealthStatus">
<work-item-health-status
class="gl-mb-5"
:health-status="workItemHealthStatus.healthStatus"
:can-update="canUpdate"
:work-item-id="workItem.id"
:work-item-iid="workItem.iid"
:work-item-type="workItemType"
:full-path="fullPath"
@error="$emit('error', $event)"
/>
</template>
<template v-if="workItemColor">
<work-item-color
class="gl-mb-5"
:work-item="workItem"
:full-path="fullPath"
:can-update="canUpdate"
@error="$emit('error', $event)"
/>
</template>
</aside>
<div class="gl-py-3 gl-flex gl-gap-3 gl-col-start-1">
<gl-button
variant="confirm"
:loading="loading"
data-testid="create-button"
@click="createWorkItem"
<gl-form-group :label="__('Confidentiality')" label-for="work-item-confidential">
<gl-form-checkbox
id="work-item-confidential"
v-model="isConfidential"
data-testid="confidential-checkbox"
@change="updateDraftData('confidential', $event)"
>
{{ makeConfidentialText }}
</gl-form-checkbox>
</gl-form-group>
</section>
<aside
v-if="hasWidgets"
data-testid="work-item-overview-right-sidebar"
class="work-item-overview-right-sidebar"
:class="{ 'is-modal': true }"
>
{{ createWorkItemText }}
</gl-button>
<gl-button type="button" data-testid="cancel-button" @click="handleCancelClick">
{{ __('Cancel') }}
</gl-button>
<template v-if="workItemAssignees">
<work-item-assignees
class="gl-mb-5 js-assignee"
:can-update="canUpdate"
:full-path="fullPath"
:work-item-id="workItem.id"
:assignees="workItemAssignees.assignees.nodes"
:participants="workItemParticipantNodes"
:work-item-author="workItemAuthor"
:allows-multiple-assignees="workItemAssignees.allowsMultipleAssignees"
:work-item-type="selectedWorkItemTypeName"
:can-invite-members="workItemAssignees.canInviteMembers"
@error="$emit('error', $event)"
/>
</template>
<template v-if="workItemHealthStatus">
<work-item-health-status
class="gl-mb-5"
:health-status="workItemHealthStatus.healthStatus"
:can-update="canUpdate"
:work-item-id="workItem.id"
:work-item-iid="workItem.iid"
:work-item-type="selectedWorkItemTypeName"
:full-path="fullPath"
@error="$emit('error', $event)"
/>
</template>
<template v-if="workItemColor">
<work-item-color
class="gl-mb-5"
:work-item="workItem"
:full-path="fullPath"
:can-update="canUpdate"
@error="$emit('error', $event)"
/>
</template>
</aside>
<div class="gl-py-3 gl-flex gl-gap-3 gl-col-start-1">
<gl-button
variant="confirm"
:loading="loading"
data-testid="create-button"
@click="createWorkItem"
>
{{ createWorkItemText }}
</gl-button>
<gl-button type="button" data-testid="cancel-button" @click="handleCancelClick">
{{ __('Cancel') }}
</gl-button>
</div>
</div>
</div>
</template>

View File

@ -97,7 +97,7 @@ export default {
:disabled="loading"
:items="items"
:selected="sortFilterProp"
placement="right"
placement="bottom-end"
size="small"
@select="fetchFilteredDiscussions"
/>

View File

@ -223,7 +223,7 @@ export default {
v-gl-tooltip
icon="ellipsis_v"
text-sr-only
placement="right"
placement="bottom-end"
:toggle-text="$options.i18n.moreActionsText"
:title="$options.i18n.moreActionsText"
category="tertiary"

View File

@ -1,7 +1,7 @@
<script>
import { GlButton } from '@gitlab/ui';
import { unionBy } from 'lodash';
import { sortNameAlphabetically } from '~/work_items/utils';
import { sortNameAlphabetically, newWorkItemId } from '~/work_items/utils';
import currentUserQuery from '~/graphql_shared/queries/current_user.query.graphql';
import usersSearchQuery from '~/graphql_shared/queries/workspace_autocomplete_users.query.graphql';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
@ -12,7 +12,7 @@ import { s__, sprintf, __ } from '~/locale';
import Tracking from '~/tracking';
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
import updateNewWorkItemMutation from '../graphql/update_new_work_item.mutation.graphql';
import { i18n, TRACKING_CATEGORY_SHOW, NEW_WORK_ITEM_GID } from '../constants';
import { i18n, TRACKING_CATEGORY_SHOW } from '../constants';
export default {
components: {
@ -236,12 +236,13 @@ export default {
this.updateInProgress = true;
const { localAssigneeIds } = this;
if (this.workItemId === NEW_WORK_ITEM_GID) {
if (this.workItemId === newWorkItemId(this.workItemType)) {
this.$apollo.mutate({
mutation: updateNewWorkItemMutation,
variables: {
input: {
isGroup: this.isGroup,
workItemType: this.workItemType,
fullPath: this.fullPath,
assignees: this.localAssignees,
},

View File

@ -70,6 +70,11 @@ export default {
required: false,
default: false,
},
workItemTypeName: {
type: String,
required: false,
default: '',
},
},
markdownDocsPath: helpPagePath('user/markdown'),
data() {
@ -99,7 +104,7 @@ export default {
},
variables() {
return {
fullPath: this.createFlow ? newWorkItemFullPath(this.fullPath) : this.fullPath,
fullPath: this.workItemFullPath,
iid: this.workItemIid,
};
},
@ -117,6 +122,11 @@ export default {
},
},
computed: {
workItemFullPath() {
return this.createFlow
? newWorkItemFullPath(this.fullPath, this.workItemTypeName)
: this.fullPath;
},
autosaveKey() {
return this.workItemId || `new-${this.workItemType}-description-draft`;
},

View File

@ -18,7 +18,7 @@ export default {
<gl-disclosure-dropdown
:toggle-text="__('Add')"
size="small"
placement="right"
placement="bottom-end"
:items="actions"
/>
</template>

View File

@ -249,7 +249,7 @@ export default {
/>
<gl-disclosure-dropdown
v-if="canUpdate && canAddTask"
placement="right"
placement="bottom-end"
size="small"
:toggle-text="$options.i18n.addChildButtonLabel"
data-testid="toggle-form"

View File

@ -6,7 +6,12 @@ import { TYPENAME_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { getBaseURL } from '~/lib/utils/url_utility';
import { convertEachWordToTitleCase } from '~/lib/utils/text_utility';
import { findHierarchyWidgetChildren, isNotesWidget, newWorkItemFullPath } from '../utils';
import {
findHierarchyWidgetChildren,
isNotesWidget,
newWorkItemFullPath,
newWorkItemId,
} from '../utils';
import {
WIDGET_TYPE_ASSIGNEES,
WIDGET_TYPE_COLOR,
@ -23,7 +28,6 @@ import {
WIDGET_TYPE_HEALTH_STATUS,
WIDGET_TYPE_DESCRIPTION,
NEW_WORK_ITEM_IID,
NEW_WORK_ITEM_GID,
} from '../constants';
import groupWorkItemByIidQuery from './group_work_item_by_iid.query.graphql';
import workItemByIidQuery from './work_item_by_iid.query.graphql';
@ -265,8 +269,8 @@ export const setNewWorkItemCache = async (
);
widgets.push({
type: 'ASSIGNEES',
allowsMultipleAssignees: assigneesWidgetData.allowsMultipleAssignees,
canInviteMembers: assigneesWidgetData.canInviteMembers,
allowsMultipleAssignees: assigneesWidgetData.allowsMultipleAssignees || false,
canInviteMembers: assigneesWidgetData.canInviteMembers || false,
assignees: {
nodes: [],
__typename: 'UserCoreConnection',
@ -398,17 +402,19 @@ export const setNewWorkItemCache = async (
? issuesListApolloProvider
: apolloProvider;
const newWorkItemPath = newWorkItemFullPath(fullPath, workItemType);
cacheProvider.clients.defaultClient.cache.writeQuery({
query: isGroup ? groupWorkItemByIidQuery : workItemByIidQuery,
variables: {
fullPath: newWorkItemFullPath(fullPath),
fullPath: newWorkItemPath,
iid: NEW_WORK_ITEM_IID,
},
data: {
workspace: {
id: newWorkItemFullPath(fullPath),
id: newWorkItemPath,
workItem: {
id: NEW_WORK_ITEM_GID,
id: newWorkItemId(workItemType),
iid: NEW_WORK_ITEM_IID,
archived: false,
title: '',
@ -422,9 +428,9 @@ export const setNewWorkItemCache = async (
reference: '',
createNoteEmail: null,
namespace: {
id: newWorkItemFullPath(fullPath),
id: newWorkItemPath,
fullPath,
name: newWorkItemFullPath(fullPath),
name: newWorkItemPath,
__typename: 'Namespace', // eslint-disable-line @gitlab/require-i18n-strings
},
author: {

View File

@ -39,6 +39,7 @@ extend type Mutation {
input LocalUpdateNewWorkItemInput {
fullPath: String!
workItemType: String!
isGroup: Boolean!
healthStatus: String
assignees: [LocalUserInput]

View File

@ -20,6 +20,7 @@ import {
WORK_ITEM_TYPE_ENUM_OBJECTIVE,
WORK_ITEM_TYPE_ENUM_KEY_RESULT,
WORK_ITEM_TYPE_ENUM_REQUIREMENTS,
NEW_WORK_ITEM_GID,
} from './constants';
export const isAssigneesWidget = (widget) => widget.type === WIDGET_TYPE_ASSIGNEES;
@ -156,11 +157,15 @@ export const workItemRoadmapPath = (fullPath, iid) => {
* Builds unique path for new work item
*
* @param {string} fullPath the path to the namespace
* @param {string} workItemType the type of work item
*/
export const newWorkItemFullPath = (fullPath) => {
export const newWorkItemFullPath = (fullPath, workItemType) => {
if (!workItemType) return undefined;
const workItemTypeLowercase = workItemType.split(' ').join('-').toLowerCase();
// eslint-disable-next-line @gitlab/require-i18n-strings
return `${fullPath}-id`;
return `${fullPath}-${workItemTypeLowercase}-id`;
};
/**
@ -183,3 +188,10 @@ export const isWorkItemItemValidEnum = (workItemType) => {
].indexOf(workItemType) >= 0
);
};
export const newWorkItemId = (workItemType) => {
if (!workItemType) return undefined;
const workItemTypeLowercase = workItemType.split(' ').join('-').toLowerCase();
return `${NEW_WORK_ITEM_GID}-${workItemTypeLowercase}`;
};

View File

@ -3,8 +3,9 @@
.gl-grow
%h2{ class: title_classes }
= heading || @heading
%p.gl-text-secondary.gl-m-0
= description || @description
- if description || @description
%p.gl-text-secondary.gl-m-0
= description || @description
.gl-shrink-0.gl-px-2
= render Pajamas::ButtonComponent.new(button_options: @button_options.merge(class: 'gl-min-w-12 js-settings-toggle')) do
= button_text

View File

@ -0,0 +1,10 @@
%section.settings-section{ id: @id, data: (@testid ? { testid: @testid } : {}) }
.settings-sticky-header
.settings-sticky-header-inner
%h2.gl-heading-2{ class: '!gl-mb-2' }
= heading || @heading
- if description || @description
%p.gl-text-secondary.gl-m-0
= description || @description
%div{ data: { testid: 'settings-section-body' } }
= body

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module Layouts
class SettingsSectionComponent < ViewComponent::Base
# @param [String] heading
# @param [String] description
# @param [String] id
# @param [String] testid
def initialize(heading, description: nil, id: nil, testid: nil)
@heading = heading
@description = description
@id = id
@testid = testid
end
renders_one :heading
renders_one :description
renders_one :body
end
end

View File

@ -20,7 +20,7 @@ module ProtectedRef
end
def commit
project.commit(self.name)
project&.commit(name)
end
class_methods do
@ -59,7 +59,7 @@ module ProtectedRef
end
def access_levels_for_ref(ref, action:, protected_refs: nil)
self.matching(ref, protected_refs: protected_refs)
matching(ref, protected_refs: protected_refs)
.flat_map(&:"#{action}_access_levels")
end
@ -70,14 +70,14 @@ module ProtectedRef
# This method optionally takes in a list of `protected_refs` to search
# through, to avoid calling out to the database.
def matching(ref_name, protected_refs: nil)
(protected_refs || self.all).select { |protected_ref| protected_ref.matches?(ref_name) }
(protected_refs || all).select { |protected_ref| protected_ref.matches?(ref_name) }
end
end
private
def ref_matcher
@ref_matcher ||= RefMatcher.new(self.name)
@ref_matcher ||= RefMatcher.new(name)
end
end

View File

@ -10,7 +10,6 @@ class ProtectedBranch < ApplicationRecord
belongs_to :group, foreign_key: :namespace_id, touch: true, inverse_of: :protected_branches
validate :validate_either_project_or_top_group
validates :name, presence: true
validates :name, uniqueness: { scope: [:project_id, :namespace_id] }, if: :name_changed?
scope :requiring_code_owner_approval, -> { where(code_owner_approval_required: true) }

View File

@ -21,8 +21,6 @@ module Ci
def execute
in_lock(EXCLUSIVE_LOCK_KEY, ttl: LOCK_TIMEOUT, retries: 1) do
destroy_unlocked_pipeline_artifacts
legacy_destroy_pipeline_artifacts
end
@removed_artifacts_count
@ -40,19 +38,6 @@ module Ci
end
end
def legacy_destroy_pipeline_artifacts
loop_until(timeout: LOOP_TIMEOUT, limit: LOOP_LIMIT) do
destroy_artifacts_batch
end
end
def destroy_artifacts_batch
artifacts = ::Ci::PipelineArtifact.unlocked.expired.limit(BATCH_SIZE).to_a
return false if artifacts.empty?
destroy_batch(artifacts)
end
def destroy_batch(artifacts)
artifacts.each(&:destroy!)
increment_stats(artifacts.size)

View File

@ -1,18 +1,13 @@
- if Gitlab.config.packages.enabled
%section.settings.as-package.no-animate#js-package-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Package Registry')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p.gl-text-secondary
= s_('PackageRegistry|Configure package forwarding and package file size limits.')
.settings-content
= render ::Layouts::SettingsBlockComponent.new(_('Package Registry'),
id: 'js-package-settings',
expanded: expanded_by_default?) do |c|
- c.with_description do
= s_('PackageRegistry|Configure package forwarding and package file size limits.')
- c.with_body do
= render_if_exists 'admin/application_settings/ee_package_registry'
= render 'admin/application_settings/nuget_skip_metadata_url_validation' unless Gitlab.ee?
.gl-mt-7
%h4
= _('Package file size limits')

View File

@ -3,161 +3,140 @@
= gitlab_ui_form_for @appearance, url: admin_application_settings_appearances_path, html: { class: 'gl-mt-3' } do |f|
= form_errors(@appearance)
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0 Favicon
.form-group
= f.label :favicon, _('Favicon'), class: 'col-form-label gl-pt-0'
%p
- if @appearance.favicon?
= image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
= render ::Layouts::SettingsSectionComponent.new(_('Favicon')) do |c|
- c.with_body do
.form-group
= f.label :favicon, _('Favicon'), class: 'col-form-label gl-pt-0'
%p
- if @appearance.favicon?
= image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do
= _('Remove favicon')
%hr
= f.hidden_field :favicon_cache
= f.file_field :favicon, class: '', accept: 'image/*'
.form-text.gl-text-secondary
= _("Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed image formats are %{favicon_extension_allowlist}.") % { favicon_extension_allowlist: favicon_extension_allowlist }
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: favicon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Favicon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove favicon') } }) do
= _('Remove favicon')
%hr
= f.hidden_field :favicon_cache
= f.file_field :favicon, class: '', accept: 'image/*'
.form-text.text-muted
= _("Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed image formats are %{favicon_extension_allowlist}.") % { favicon_extension_allowlist: favicon_extension_allowlist }
%br
= _("Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior.")
= _("Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior.")
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('Member guidelines')
.form-text.text-muted
= render ::Layouts::SettingsSectionComponent.new(_('Member guidelines')) do |c|
- c.with_description do
= _('These guidelines are displayed on the group\'s or project\'s members page, and are visible to users who can manage team member permissions.')
- c.with_body do
.form-group
= f.label :member_guidelines, class: 'col-form-label'
%p
= f.text_area :member_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.gl-text-secondary
= parsed_with_gfm
.form-group
= f.label :member_guidelines, class: 'col-form-label'
%p
= f.text_area :member_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
= parsed_with_gfm
= render ::Layouts::SettingsSectionComponent.new(_('Navigation bar')) do |c|
- c.with_body do
.form-group
= f.label :header_logo, _('Header logo'), class: 'col-form-label gl-pt-0'
%p
- if @appearance.header_logo?
= image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: header_logos_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') } }) do
= _('Remove header logo')
%hr
= f.hidden_field :header_logo_cache
= f.file_field :header_logo, class: "", accept: 'image/*'
.form-text.gl-text-secondary
= _('Maximum file size is 1MB. Pages are optimized for a 24px tall header logo')
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('Navigation bar')
.form-group
= f.label :header_logo, _('Header logo'), class: 'col-form-label gl-pt-0'
%p
- if @appearance.header_logo?
= image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: header_logos_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Header logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove header logo') } }) do
= _('Remove header logo')
%hr
= f.hidden_field :header_logo_cache
= f.file_field :header_logo, class: "", accept: 'image/*'
.form-text.text-muted
= _('Maximum file size is 1MB. Pages are optimized for a 24px tall header logo')
= render ::Layouts::SettingsSectionComponent.new(_('New project pages')) do |c|
- c.with_body do
.form-group
= f.label :new_project_guidelines, class: 'col-form-label'
%p
= f.text_area :new_project_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.gl-text-secondary
= parsed_with_gfm
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('New project pages')
.form-group
= f.label :new_project_guidelines, class: 'col-form-label'
%p
= f.text_area :new_project_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
= parsed_with_gfm
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('Profile image guidelines')
%p.gl-text-secondary
= render ::Layouts::SettingsSectionComponent.new(_('Profile image guidelines')) do |c|
- c.with_description do
= _('These guidelines for public avatars are displayed on the user settings page.')
- c.with_body do
.form-group
= f.label :profile_image_guidelines, class: 'col-form-label'
%p
= f.text_area :profile_image_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.gl-text-secondary
= parsed_with_gfm
.form-group
= f.label :profile_image_guidelines, class: 'col-form-label'
%p
= f.text_area :profile_image_guidelines, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
= render ::Layouts::SettingsSectionComponent.new(_('Progressive Web App (PWA)')) do |c|
- c.with_body do
.form-group
= f.label _("Name"), class: 'col-form-label'
= f.text_field :pwa_name, class: "form-control gl-form-input"
.form-group
= f.label _("Short name"), class: 'col-form-label'
= f.text_field :pwa_short_name, class: "form-control gl-form-input"
.form-group
= f.label _("Description"), class: 'col-form-label'
= f.text_area :pwa_description, class: "form-control gl-form-input", rows: 10
.form-text.gl-text-secondary
= parsed_with_gfm
.form-group
= f.label :pwa_icon, class: 'col-form-label gl-pt-0'
%p
- if @appearance.pwa_icon?
= image_tag @appearance.pwa_icon_path, class: 'appearance-pwa-icon-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: pwa_icon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') } }) do
= _('Remove icon')
%hr
= f.hidden_field :pwa_icon_cache
= f.file_field :pwa_icon, class: "", accept: 'image/*'
.form-text.gl-text-secondary
= _('Maximum file size is 1MB.')
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('Progressive Web App (PWA)')
.form-group
= f.label _("Name"), class: 'col-form-label'
= f.text_field :pwa_name, class: "form-control gl-form-input"
.form-group
= f.label _("Short name"), class: 'col-form-label'
= f.text_field :pwa_short_name, class: "form-control gl-form-input"
.form-group
= f.label _("Description"), class: 'col-form-label'
= f.text_area :pwa_description, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
= parsed_with_gfm
.form-group
= f.label :pwa_icon, class: 'col-form-label gl-pt-0'
%p
- if @appearance.pwa_icon?
= image_tag @appearance.pwa_icon_path, class: 'appearance-pwa-icon-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: pwa_icon_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Icon will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove icon') } }) do
= _('Remove icon')
%hr
= f.hidden_field :pwa_icon_cache
= f.file_field :pwa_icon, class: "", accept: 'image/*'
.form-text.text-muted
= _('Maximum file size is 1MB.')
.settings-section
.settings-sticky-header
.settings-sticky-header-inner
%h4.gl-my-0= _('Sign in/Sign up pages')
.form-group
= f.label :title, class: 'col-form-label'
= f.text_field :title, class: "form-control gl-form-input"
.form-group
= f.label :description, class: 'col-form-label'
= f.text_area :description, class: "form-control gl-form-input", rows: 10
.form-text.text-muted
= parsed_with_gfm
.form-group
= f.label :logo, class: 'col-form-label gl-pt-0'
%p
- if @appearance.logo?
= image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do
= _('Remove logo')
%hr
= f.hidden_field :logo_cache
= f.file_field :logo, class: "", accept: 'image/*'
.form-text.text-muted
= _('Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo.')
= render ::Layouts::SettingsSectionComponent.new(_('Sign in/Sign up pages')) do |c|
- c.with_body do
.form-group
= f.label :title, class: 'col-form-label'
= f.text_field :title, class: "form-control gl-form-input"
.form-group
= f.label :description, class: 'col-form-label'
= f.text_area :description, class: "form-control gl-form-input", rows: 10
.form-text.gl-text-secondary
= parsed_with_gfm
.form-group
= f.label :logo, class: 'col-form-label gl-pt-0'
%p
- if @appearance.logo?
= image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- if @appearance.persisted?
%br
= render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, size: :small, method: :delete, href: logo_admin_application_settings_appearances_path, button_options: { data: { confirm: _("Logo will be removed. Are you sure?"), confirm_btn_variant: "danger" }, aria: { label: _('Remove logo') } }) do
= _('Remove logo')
%hr
= f.hidden_field :logo_cache
= f.file_field :logo, class: "", accept: 'image/*'
.form-text.gl-text-secondary
= _('Maximum file size is 1 MB. Pages are optimized for a 128x128 px logo.')
= render partial: 'admin/application_settings/appearances/system_header_footer_form', locals: { form: f }
- if @appearance.persisted? || @appearance.updated_at
.settings-section
- if @appearance.persisted?
Preview last save:
= s_('AppearanceSettings|Preview last save:')
= link_to _('Sign-in page'), preview_sign_in_admin_application_settings_appearances_path, class: 'btn', target: '_blank', rel: 'noopener noreferrer'
= link_to _('New project page'), new_project_path, class: 'btn', target: '_blank', rel: 'noopener noreferrer'
- if @appearance.updated_at
%span.gl-float-right
Last edit #{time_ago_with_tooltip(@appearance.updated_at)}
%span.gl-float-right.gl-text-secondary
= s_('AppearanceSettings|Last edit')
#{time_ago_with_tooltip(@appearance.updated_at)}
.settings-sticky-footer
= f.submit _('Update appearance settings'), pajamas_button: true

View File

@ -1,11 +0,0 @@
- expanded = local_assigns.fetch(:expanded)
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Variables')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded ? _('Collapse') : _('Expand')
%p.gl-text-secondary
= s_('CiVariables|Variables store information that you can use in job scripts. All projects on the instance can use these variables.')
= link_to _('Learn more.'), help_page_path('ci/variables/index', anchor: 'for-an-instance'), target: '_blank', rel: 'noopener noreferrer'

View File

@ -3,10 +3,13 @@
- add_page_specific_style 'page_bundles/settings'
- @force_desktop_expanded_sidebar = true
%section.settings.no-animate#js-ci-cd-variables{ class: ('expanded' if expanded_by_default?) }
.settings-header
= render 'admin/application_settings/ci/header', expanded: expanded_by_default?
.settings-content
= render ::Layouts::SettingsBlockComponent.new(_('Variables'),
id: 'js-ci-cd-variables',
expanded: expanded_by_default?) do |c|
- c.with_description do
= s_('CiVariables|Variables store information that you can use in job scripts. All projects on the instance can use these variables.')
= link_to _('Learn more.'), help_page_path('ci/variables/index', anchor: 'for-an-instance'), target: '_blank', rel: 'noopener noreferrer'
- c.with_body do
= render 'ci/variables/attributes'
- if ci_variable_protected_by_default?
%p.settings-message.gl-text-center
@ -14,35 +17,32 @@
= safe_format(s_('Environment variables on this GitLab instance are configured to be %{help_link_start}protected%{help_link_end} by default.'), tag_pair(help_link, :help_link_start, :help_link_end))
#js-instance-variables{ data: { endpoint: admin_ci_variables_path, maskable_regex: ci_variable_maskable_regex, protected_by_default: ci_variable_protected_by_default?.to_s} }
%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Continuous Integration and Deployment')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p.gl-text-secondary
= _('Customize CI/CD settings, including Auto DevOps, instance runners, and job artifacts.')
= render 'ci_cd'
= render ::Layouts::SettingsBlockComponent.new(_('Continuous Integration and Deployment'),
id: 'js-continuous-integration-settings',
testid: 'ci-cd-settings',
expanded: expanded_by_default?) do |c|
- c.with_description do
= _('Customize CI/CD settings, including Auto DevOps, instance runners, and job artifacts.')
- c.with_body do
= render 'ci_cd'
= render_if_exists 'admin/application_settings/package_registry', expanded: expanded_by_default?
- if Gitlab.config.registry.enabled
%section.settings.as-registry.no-animate#js-registry-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Container Registry')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p.gl-text-secondary
= _('Various container registry settings.')
.settings-content
= render ::Layouts::SettingsBlockComponent.new(_('Container Registry'),
id: 'js-registry-settings',
testid: 'registry-settings',
expanded: expanded_by_default?) do |c|
- c.with_description do
= _('Various container registry settings.')
- c.with_body do
= render 'registry'
%section.settings.as-runner.no-animate#js-runner-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= s_('Runners|Runners')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? 'Collapse' : 'Expand'
.settings-content
= render ::Layouts::SettingsBlockComponent.new(s_('Runners|Runners'),
id: 'js-runner-settings',
testid: 'runner-settings',
expanded: expanded_by_default?) do |c|
- c.with_description do
= _('Configure runner version management and registration settings.')
- c.with_body do
= render 'runner_registrars_form'

View File

@ -27,7 +27,7 @@
&nbsp;
%tr.section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "text-align: left; width:100%;" }
%tbody
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" }= _("Project")

View File

@ -28,7 +28,7 @@
&nbsp;
%tr.section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "text-align: left; width:100%;" }
%tbody
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" }= _('Project')

View File

@ -28,7 +28,7 @@
&nbsp;
%tr.section
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" }
%table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "text-align: left; width:100%;" }
%tbody
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" }

View File

@ -12,4 +12,4 @@
- if setting
.js-vue-notification-dropdown{ data: { disabled: emails_disabled.to_s, dropdown_items: notification_dropdown_items(setting).to_json, notification_level: setting.level, help_page_path: help_page_path('user/profile/notifications'), group_id: group.id, show_label: "true" } }
= form_for setting, url: profile_group_notifications_path(group), method: :put, html: { class: 'update-notifications gl-display-flex' } do |f|
.js-notification-email-listbox-input{ data: { name: 'notification_setting[notification_email]', emails: @user.public_verified_emails.to_json, empty_value_text: _('Global notification email') , value: setting.notification_email, placement: 'right' } }
.js-notification-email-listbox-input{ data: { name: 'notification_setting[notification_email]', emails: @user.public_verified_emails.to_json, empty_value_text: _('Global notification email') , value: setting.notification_email, placement: 'bottom-end' } }

View File

@ -11,5 +11,4 @@
project_name: @project.name,
project_path: @project.root_ancestor.full_path,
gitlab_host: Gitlab.config.gitlab.host,
terraform_help_path: help_page_path('user/infrastructure/index'),
project_list_url: project_infrastructure_registry_index_path(@project)} }

View File

@ -1,12 +1,12 @@
---
migration_job_name: BackfillSbomOccurrencesTraversalIdsAndArchived
description: >
Backfills sbom_occurrences.traversal_ids and sbom_occurrences.archived columns with
values from sbom_occurrences.project.namespace.traversal_ids and
sbom_occurrences.project.archived.
description: 'Backfills sbom_occurrences.traversal_ids and sbom_occurrences.archived
columns with values from sbom_occurrences.project.namespace.traversal_ids and sbom_occurrences.project.archived.
'
feature_category: dependency_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144802
milestone: '16.10'
queued_migration_version: 20240214203242
finalize_after: '2024-04-11'
finalized_by: # Not yet implemented
finalized_by: '20240626231944'

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class RemoveMemberRolesIndividualPermissionsColumns < Gitlab::Database::Migration[2.2]
milestone '17.2'
PERMISSION_COLUMNS = %i[
admin_cicd_variables
admin_group_member
admin_merge_request
admin_terraform_state
admin_vulnerability
archive_project
manage_group_access_tokens
manage_project_access_tokens
read_code
read_dependency
read_vulnerability
remove_group
remove_project
]
def change
remove_columns :member_roles, *PERMISSION_COLUMNS, type: :boolean, null: false, default: false
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class DropIndexSecurityFindingsConfidenceIdx < Gitlab::Database::Migration[2.2]
include Gitlab::Database::PartitioningMigrationHelpers
disable_ddl_transaction!
milestone '17.2'
INDEX_NAME = 'security_findings_confidence_idx'
TABLE_NAME = :security_findings
def up
remove_concurrent_partitioned_index_by_name TABLE_NAME, INDEX_NAME
end
def down
add_concurrent_partitioned_index TABLE_NAME, :confidence, name: INDEX_NAME
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class FinalizeBackfillSbomOccurrencesTraversalIdsAndArchived < Gitlab::Database::Migration[2.2]
milestone '17.2'
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
ensure_batched_background_migration_is_finished(
job_class_name: 'BackfillSbomOccurrencesTraversalIdsAndArchived',
table_name: :sbom_occurrences,
column_name: :id,
job_arguments: [],
finalize: true
)
end
def down; end
end

View File

@ -0,0 +1 @@
ba1a13140ac43c4640f2cb49bb1d162ed36751ba35cf66c45f49b3410a23507a

View File

@ -0,0 +1 @@
3375b9d5de363d25c4be4669a94a68dbce9cec8a5e6954f01926057163e5650a

View File

@ -0,0 +1 @@
767d2d4a0f15dfe73608c8db586777a1f55014d3e66f599e719ba3c997364a0d

View File

@ -12177,21 +12177,8 @@ CREATE TABLE member_roles (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
base_access_level integer NOT NULL,
read_code boolean DEFAULT false,
read_vulnerability boolean DEFAULT false NOT NULL,
admin_vulnerability boolean DEFAULT false NOT NULL,
read_dependency boolean DEFAULT false NOT NULL,
name text DEFAULT 'Custom'::text NOT NULL,
description text,
admin_merge_request boolean DEFAULT false NOT NULL,
admin_group_member boolean DEFAULT false NOT NULL,
manage_project_access_tokens boolean DEFAULT false NOT NULL,
archive_project boolean DEFAULT false NOT NULL,
manage_group_access_tokens boolean DEFAULT false NOT NULL,
remove_project boolean DEFAULT false NOT NULL,
admin_terraform_state boolean DEFAULT false NOT NULL,
admin_cicd_variables boolean DEFAULT false NOT NULL,
remove_group boolean DEFAULT false NOT NULL,
occupies_seat boolean DEFAULT false NOT NULL,
permissions jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT check_4364846f58 CHECK ((char_length(description) <= 255)),
@ -29649,8 +29636,6 @@ CREATE INDEX scan_finding_approval_project_rule_index_created_at_project_id ON a
CREATE INDEX scan_finding_approval_project_rule_index_project_id ON approval_project_rules USING btree (project_id) WHERE (report_type = 4);
CREATE INDEX security_findings_confidence_idx ON ONLY security_findings USING btree (confidence);
CREATE INDEX security_findings_project_fingerprint_idx ON ONLY security_findings USING btree (project_fingerprint);
CREATE INDEX security_findings_scan_id_deduplicated_idx ON ONLY security_findings USING btree (scan_id, deduplicated);

View File

@ -615,6 +615,8 @@ flow of how we construct a Chat prompt:
GitLab Duo Chat has error codes with specified meanings to assist in debugging.
Currently, they are only logged, but in the future, they will be displayed on the UI.
See the [GitLab Duo Chat troubleshooting documentation](../../user/gitlab_duo_chat/troubleshooting.md) for a list of all GitLab Duo Chat error codes.
When developing for GitLab Duo Chat, please include these error codes when returning an error and [document them](../../user/gitlab_duo_chat/troubleshooting.md), especially for user-facing errors.
### Error Code Format

View File

@ -230,10 +230,13 @@ To update the linting images:
1. In `gitlab-docs`, open a merge request to update `.gitlab-ci.yml` to use the new tooling
version. ([Example MR](https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/2571))
1. When merged, start a `Build docs.gitlab.com every hour` [scheduled pipeline](https://gitlab.com/gitlab-org/gitlab-docs/-/pipeline_schedules).
1. Go the pipeline you started, and manually run the relevant build-images job,
for example, `image:docs-lint-markdown`.
1. In the job output, get the name of the new image.
1. When merged, start a `Build docker images manually` [scheduled pipeline](https://gitlab.com/gitlab-org/gitlab-docs/-/pipeline_schedules).
1. Go the pipeline you started, and wait for the relevant `test:image` job to complete,
for example `test:image:docs-lint-markdown`. If the job:
- Passes, start the relevant `image:` job, for example, `image:docs-lint-markdown`.
- Fails, review the test job log and start troubleshooting the issue. The image configuration
likely needs some manual tweaks to work with the updated dependency.
1. After the `image:` job passes, check the job's log for the name of the new image.
([Example job output](https://gitlab.com/gitlab-org/gitlab-docs/-/jobs/2335033884#L334))
1. Verify that the new image was added to the container registry.
1. Open merge requests to update each of these configuration files to point to the new image.

View File

@ -747,55 +747,64 @@ When GitLab receives a SAML response from a SAML SSO provider, GitLab looks for
You must include these values correctly in the attribute `Name` field so that GitLab can parse the SAML response. For example, GitLab can parse the following SAML response snippets:
```xml
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
- This is accepted because the `Name` attribute is set to one of the required values from the previous table.
```xml
<Attribute Name="firstname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="lastname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="email">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
```xml
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
- This is accepted because the `Name` attribute matches one of the values from the previous table.
```xml
<Attribute Name="firstname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="lastname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="email">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
However, GitLab cannot parse the following SAML response snippets:
```xml
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/firstname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/lastname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mail">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
- This will not be accepted because value in the `Name` attribute is not one of the supported
values in the previous table.
```xml
<Attribute FriendlyName="firstname" Name="urn:oid:2.5.4.42">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute FriendlyName="lastname" Name="urn:oid:2.5.4.4">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute FriendlyName="email" Name="urn:oid:0.9.2342.19200300.100.1.3">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
```xml
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/firstname">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/lastname">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/mail">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
- This will fail because, even though the `FriendlyName` has a supported value, the `Name` attribute does not.
```xml
<Attribute FriendlyName="firstname" Name="urn:oid:2.5.4.42">
<AttributeValue>Alvin</AttributeValue>
</Attribute>
<Attribute FriendlyName="lastname" Name="urn:oid:2.5.4.4">
<AttributeValue>Test</AttributeValue>
</Attribute>
<Attribute FriendlyName="email" Name="urn:oid:0.9.2342.19200300.100.1.3">
<AttributeValue>alvintest@example.com</AttributeValue>
</Attribute>
```
See [`attribute_statements`](#map-saml-response-attribute-names) for:

View File

@ -6341,6 +6341,12 @@ msgstr ""
msgid "Appearance was successfully updated."
msgstr ""
msgid "AppearanceSettings|Last edit"
msgstr ""
msgid "AppearanceSettings|Preview last save:"
msgstr ""
msgid "Append the comment with %{shrug}"
msgstr ""
@ -13991,6 +13997,9 @@ msgstr ""
msgid "Configure repository storage."
msgstr ""
msgid "Configure runner version management and registration settings."
msgstr ""
msgid "Configure settings for Advanced Search with Elasticsearch."
msgstr ""

View File

@ -215,14 +215,14 @@
"url-loader": "^4.1.1",
"uuid": "8.1.0",
"visibilityjs": "^1.2.4",
"vue": "2.7.15",
"vue": "2.7.16",
"vue-apollo": "^3.0.7",
"vue-loader": "15.11.1",
"vue-observe-visibility": "^1.0.0",
"vue-resize": "^1.0.1",
"vue-router": "3.6.5",
"vue-router-vue3": "npm:vue-router@4.1.6",
"vue-template-compiler": "2.7.15",
"vue-template-compiler": "2.7.16",
"vue-virtual-scroll-list": "^1.4.7",
"vuedraggable": "^2.23.0",
"vuex": "^3.6.2",

View File

@ -1,8 +1,8 @@
diff --git a/node_modules/vue/node_modules/@vue/compiler-sfc/dist/compiler-sfc.js b/node_modules/vue/node_modules/@vue/compiler-sfc/dist/compiler-sfc.js
index ec32339..91e43a7 100644
index 91da3e0..001cf4f 100644
--- a/node_modules/vue/node_modules/@vue/compiler-sfc/dist/compiler-sfc.js
+++ b/node_modules/vue/node_modules/@vue/compiler-sfc/dist/compiler-sfc.js
@@ -9645,7 +9645,23 @@ const splitRE = /\r?\n/g;
@@ -9658,7 +9658,23 @@ const splitRE = /\r?\n/g;
const emptyRE = /^(?:\/\/)?\s*$/;
function parse(options) {
const { source, filename = DEFAULT_FILENAME, compiler, compilerParseOptions = { pad: false }, sourceRoot = '', needMap = true, sourceMap = needMap } = options;

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Layouts::SettingsSectionComponent, type: :component, feature_category: :shared do
let(:heading) { 'Settings section heading' }
let(:description) { 'Settings section description' }
let(:body) { 'Settings section content' }
let(:id) { 'js-settings-section-id' }
let(:testid) { 'settings-section-testid' }
describe 'slots' do
it 'renders heading' do
render_inline described_class.new(heading)
expect(page).to have_css('h2.gl-heading-2', text: heading)
end
it 'renders description' do
render_inline described_class.new(heading, description: description)
expect(page).to have_css('.gl-text-secondary', text: description)
end
it 'renders description slot' do
render_inline described_class.new(heading) do |c|
c.with_description { description }
end
expect(page).to have_css('.gl-text-secondary', text: description)
end
it 'renders body slot' do
render_inline described_class.new(heading) do |c|
c.with_body { body }
end
expect(page).to have_css('[data-testid="settings-section-body"]', text: body)
end
it 'renders id' do
render_inline described_class.new(heading, id: id)
expect(page).to have_css('#js-settings-section-id')
end
it 'renders testid' do
render_inline described_class.new(heading, testid: testid)
expect(page).to have_css('[data-testid="settings-section-testid"]')
end
end
end

Some files were not shown because too many files have changed in this diff Show More