Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-02-22 12:11:46 +00:00
parent c2114645bb
commit dc66c37ac3
85 changed files with 680 additions and 397 deletions

View File

@ -1,5 +1,4 @@
---
Gitlab/TokenWithoutPrefix:
Details: grace period
Exclude:
- 'app/models/application_setting.rb'

View File

@ -129,7 +129,7 @@ export default {
<template #head(lastUsedAt)="{ label }">
<span>{{ label }}</span>
<gl-link :href="$options.lastUsedHelpLink"
><gl-icon name="question-o" /><span class="gl-sr-only">{{
><gl-icon name="question-o" class="gl-ml-2" /><span class="gl-sr-only">{{
s__('AccessTokens|The last time a token was used')
}}</span></gl-link
>

View File

@ -21,7 +21,6 @@ import AlertStatus from '~/vue_shared/alert_details/components/alert_status.vue'
import { TOKEN_TYPE_ASSIGNEE } from '~/vue_shared/components/filtered_search_bar/constants';
import {
tdClass,
thClass,
bodyTrClass,
initialPaginationState,
} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants';
@ -53,7 +52,8 @@ export default {
{
key: 'severity',
label: s__('AlertManagement|Severity'),
thClass: `${thClass} gl-w-eighth`,
variant: 'secondary',
thClass: `gl-w-eighth`,
thAttr: TH_TEST_ID,
tdClass: `${tdClass} rounded-top text-capitalize sortable-cell`,
sortable: true,
@ -61,7 +61,8 @@ export default {
{
key: 'startedAt',
label: s__('AlertManagement|Start time'),
thClass: `${thClass} js-started-at w-15p`,
variant: 'secondary',
thClass: `js-started-at w-15p`,
tdClass: `${tdClass} sortable-cell`,
sortable: true,
},
@ -74,8 +75,8 @@ export default {
{
key: 'eventCount',
label: s__('AlertManagement|Events'),
thClass: `${thClass} text-right gl-w-12`,
tdClass: `${tdClass} text-md-right sortable-cell`,
variant: 'secondary',
tdClass: `${tdClass} sortable-cell`,
sortable: true,
},
{
@ -93,7 +94,8 @@ export default {
{
key: 'status',
label: s__('AlertManagement|Status'),
thClass: `${thClass} w-15p`,
variant: 'secondary',
thClass: `w-15p`,
tdClass: `${tdClass} rounded-bottom sortable-cell`,
sortable: true,
},
@ -329,8 +331,10 @@ export default {
:sort-direction="sortDirection"
:sort-desc.sync="sortDesc"
:sort-by.sync="sortBy"
sort-icon-left
fixed
hover
selectable
selected-variant="primary"
@row-clicked="navigateToAlertDetails"
@sort-changed="fetchSortedData"
>

View File

@ -211,7 +211,7 @@ export default {
>
<template v-if="stageCount" #head(title)="data">
<span>{{ data.label }}</span
><gl-badge class="gl-ml-2" size="sm"
><gl-badge class="gl-ml-3" size="sm"
><formatted-stage-count :stage-count="stageCount"
/></gl-badge>
</template>

View File

@ -269,7 +269,6 @@ export default {
stacked="md"
fixed
show-empty
sort-icon-left
no-sort-reset
no-local-sorting
@sort-changed="(val) => $emit('sort-changed', val)"

View File

@ -238,7 +238,6 @@ export default {
stacked="md"
table-class="text-secondary"
show-empty
sort-icon-left
no-sort-reset
:empty-text="$options.i18n.noFilesMessage"
>

View File

@ -231,7 +231,6 @@ export default {
sort-by="createdAt"
show-empty
no-local-sorting
sort-icon-left
fixed
@sort-changed="fetchSortedData"
>

View File

@ -222,7 +222,6 @@ export default {
sort-by="createdAt"
show-empty
no-local-sorting
sort-icon-left
fixed
@sort-changed="fetchSortedData"
>

View File

@ -1,41 +0,0 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import ForksButton from './components/forks_button.vue';
const initForksButton = () => {
const el = document.getElementById('js-forks-button');
if (!el) {
return false;
}
const {
forksCount,
projectFullPath,
projectForksUrl,
userForkUrl,
newForkUrl,
canReadCode,
canCreateFork,
canForkProject,
} = el.dataset;
return new Vue({
el,
provide: {
forksCount,
projectFullPath,
projectForksUrl,
userForkUrl,
newForkUrl,
canReadCode: parseBoolean(canReadCode),
canCreateFork: parseBoolean(canCreateFork),
canForkProject: parseBoolean(canForkProject),
},
render(createElement) {
return createElement(ForksButton);
},
});
};
export default initForksButton;

View File

@ -23,7 +23,7 @@ export default {
},
inject: [
'isGroup',
'id',
'groupOrProjectId',
'leavePath',
'leaveConfirmMessage',
'withdrawPath',
@ -90,7 +90,7 @@ export default {
},
copyIdItem() {
return {
text: sprintf(this.copyTitle, { id: this.id }),
text: sprintf(this.copyTitle, { id: this.groupOrProjectId }),
action: () => {
this.$toast.show(this.copiedToClipboard);
},
@ -148,7 +148,11 @@ export default {
</div>
</template>
<gl-disclosure-dropdown-item v-if="id" :item="copyIdItem" :data-clipboard-text="id" />
<gl-disclosure-dropdown-item
v-if="groupOrProjectId"
:item="copyIdItem"
:data-clipboard-text="groupOrProjectId"
/>
<gl-disclosure-dropdown-group v-if="hasPath" bordered>
<gl-disclosure-dropdown-item v-if="leavePath" ref="leaveItem" :item="leaveItem" />

View File

@ -24,7 +24,7 @@ export default function InitMoreActionsDropdown() {
name: 'MoreActionsDropdownRoot',
provide: {
isGroup: parseBoolean(isGroup),
id,
groupOrProjectId: id,
leavePath,
leaveConfirmMessage,
withdrawPath,

View File

@ -45,12 +45,17 @@ export default {
required: false,
default: null,
},
fullPath: {
type: String,
required: false,
default: null,
},
},
computed: {
title() {
return sprintf(s__('BulkImport|Items that failed to be imported for %{id}'), {
id: this.entityId,
id: this.fullPath || this.entityId,
});
},
},

View File

@ -20,7 +20,6 @@ import SeverityToken from '~/sidebar/components/severity/severity.vue';
import Tracking from '~/tracking';
import {
tdClass,
thClass,
bodyTrClass,
initialPaginationState,
} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants';
@ -54,7 +53,8 @@ export default {
{
key: 'severity',
label: s__('IncidentManagement|Severity'),
thClass: `${thClass} gl-w-15p`,
variant: 'secondary',
thClass: `gl-w-15p`,
tdClass: `${tdClass} sortable-cell`,
actualSortKey: 'SEVERITY',
sortable: true,
@ -69,7 +69,8 @@ export default {
{
key: 'escalationStatus',
label: s__('IncidentManagement|Status'),
thClass: `${thClass} gl-w-eighth`,
variant: 'secondary',
thClass: `gl-w-eighth`,
tdClass: `${tdClass} sortable-cell`,
actualSortKey: 'ESCALATION_STATUS',
sortable: true,
@ -78,7 +79,8 @@ export default {
{
key: 'createdAt',
label: s__('IncidentManagement|Date created'),
thClass: `${thClass} gl-w-eighth`,
variant: 'secondary',
thClass: `gl-w-eighth`,
tdClass: `${tdClass} sortable-cell`,
actualSortKey: 'CREATED',
sortable: true,
@ -87,7 +89,8 @@ export default {
{
key: 'incidentSla',
label: s__('IncidentManagement|Time to SLA'),
thClass: `${thClass} gl-text-right gl-w-10p`,
variant: 'secondary',
thClass: `gl-text-right gl-w-10p`,
tdClass: `${tdClass} gl-text-right`,
thAttr: TH_INCIDENT_SLA_TEST_ID,
actualSortKey: 'SLA_DUE_AT',
@ -102,7 +105,8 @@ export default {
{
key: 'published',
label: s__('IncidentManagement|Published'),
thClass: `${thClass} gl-w-15`,
variant: 'secondary',
thClass: `gl-w-15`,
tdClass: `${tdClass} sortable-cell`,
actualSortKey: 'PUBLISHED',
sortable: true,
@ -388,8 +392,10 @@ export default {
sort-by="createdAt"
show-empty
no-local-sorting
sort-icon-left
fixed
hover
selectable
selected-variant="primary"
@row-clicked="navigateToIncidentDetails"
@sort-changed="fetchSortedData"
>

View File

@ -21,7 +21,7 @@ export default {
containerClass: {
default: '',
},
disabled: {
emailsDisabled: {
default: false,
},
dropdownItems: {
@ -81,7 +81,7 @@ export default {
this.$options.i18n.notificationTitles[this.selectedNotificationLevel] ||
this.selectedNotificationLevel;
return this.disabled
return this.emailsDisabled
? this.$options.i18n.notificationDescriptions.owner_disabled
: sprintf(this.$options.i18n.notificationTooltipTitle, {
notification_title: notificationTitle,
@ -127,7 +127,7 @@ export default {
:size="buttonSize"
:icon="buttonIcon"
:loading="isLoading"
:disabled="disabled"
:disabled="emailsDisabled"
:split="isCustomNotification"
:text="buttonText"
:no-flip="noFlip"

View File

@ -60,7 +60,7 @@ export default () => {
provide: {
containerClass,
buttonSize,
disabled: parseBoolean(disabled),
emailsDisabled: parseBoolean(disabled),
dropdownItems: JSON.parse(dropdownItems),
initialNotificationLevel: notificationLevel,
helpPagePath,

View File

@ -1,10 +1,16 @@
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
#import "../fragments/organization.fragment.graphql"
query getCurrentUserOrganizations($first: Int, $last: Int, $before: String, $after: String) {
query getCurrentUserOrganizations(
$search: String
$first: Int
$last: Int
$before: String
$after: String
) {
currentUser {
id
organizations(first: $first, last: $last, before: $before, after: $after) {
organizations(search: $search, first: $first, last: $last, before: $before, after: $after) {
nodes {
...Organization
}

View File

@ -15,7 +15,9 @@ export default {
createdByPipelineText: s__(
'PackageRegistry|Built by pipeline %{link} triggered %{datetime} by %{author}',
),
publishText: s__('PackageRegistry|Published to the %{project} Package Registry %{datetime}'),
publishText: s__(
'PackageRegistry|Published to the %{project} Terraform Module Registry %{datetime}',
),
combinedUpdateText: s__(
'PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}',
),

View File

@ -8,7 +8,7 @@ export const initBulkImportDetails = () => {
return null;
}
const { id, entityId } = el.dataset;
const { id, entityId, fullPath } = el.dataset;
return new Vue({
el,
@ -18,6 +18,7 @@ export const initBulkImportDetails = () => {
props: {
id,
entityId,
fullPath,
},
});
},

View File

@ -0,0 +1,61 @@
<script>
import { s__, sprintf } from '~/locale';
import { isLoggedIn } from '~/lib/utils/common_utils';
import ForksButton from '~/forks/components/forks_button.vue';
import MoreActionsDropdown from '~/groups_projects/components/more_actions_dropdown.vue';
import NotificationsDropdown from '~/notifications/components/notifications_dropdown.vue';
import StarCount from '~/stars/components/star_count.vue';
export default {
components: {
ForksButton,
MoreActionsDropdown,
NotificationsDropdown,
StarCount,
},
inject: {
canReadProject: {
default: false,
},
isProjectEmpty: {
default: false,
},
projectId: {
default: '',
},
},
data() {
return {
isLoggedIn: isLoggedIn(),
};
},
computed: {
canForkProject() {
return !this.isProjectEmpty && isLoggedIn() && this.canReadProject;
},
copyProjectId() {
return sprintf(s__('ProjectPage|Project ID: %{id}'), { id: this.projectId });
},
},
};
</script>
<template>
<div class="gl-display-flex gl-gap-3">
<template v-if="isLoggedIn && canReadProject">
<notifications-dropdown />
</template>
<star-count />
<forks-button v-if="canForkProject" />
<template v-if="canReadProject">
<span class="gl-sr-only" itemprop="identifier" data-testid="project-id-content">
{{ copyProjectId }}
</span>
</template>
<more-actions-dropdown />
</div>
</template>

View File

@ -0,0 +1,106 @@
import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import HomePanel from './components/home_panel.vue';
Vue.use(GlToast);
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
const initHomePanel = () => {
const container = document.getElementById('js-home-panel');
if (container === null) {
return null;
}
const {
// HomePanel component
canReadProject,
isProjectEmpty,
projectId,
// Dropdown component
isGroup,
leaveConfirmMessage,
leavePath,
requestAccessPath,
withdrawConfirmMessage,
withdrawPath,
// Fork component
canCreateFork,
canForkProject,
canReadCode,
forksCount,
newForkUrl,
projectForksUrl,
projectFullPath,
userForkUrl,
// Notification component
emailsDisabled,
notificationDropdownItems,
notificationHelpPagePath,
notificationLevel,
// Star component
signInPath,
starCount,
starred,
starrersPath,
} = container.dataset;
return new Vue({
apolloProvider,
el: container,
name: 'HomePanelRoot',
provide: {
// HomePanel component
canReadProject: parseBoolean(canReadProject),
isProjectEmpty: parseBoolean(isProjectEmpty),
projectId,
// Dropdown component
groupOrProjectId: projectId,
isGroup: parseBoolean(isGroup),
leaveConfirmMessage,
leavePath,
requestAccessPath,
withdrawConfirmMessage,
withdrawPath,
// Fork component
canCreateFork: parseBoolean(canCreateFork),
canForkProject: parseBoolean(canForkProject),
canReadCode: parseBoolean(canReadCode),
forksCount: parseInt(forksCount, 10) || 0,
newForkUrl,
projectForksUrl,
projectFullPath,
userForkUrl,
// Notification component
dropdownItems: JSON.parse(notificationDropdownItems || null),
emailsDisabled: parseBoolean(emailsDisabled),
helpPagePath: notificationHelpPagePath,
initialNotificationLevel: notificationLevel,
noFlip: true,
// Star component
signInPath,
starCount: parseInt(starCount, 10) || 0,
starred: parseBoolean(starred),
starrersPath,
},
render: (createElement) => createElement(HomePanel),
});
};
export { initHomePanel };

View File

@ -3,15 +3,12 @@ import { addShortcutsExtension } from '~/behaviors/shortcuts';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initClustersDeprecationAlert from '~/projects/clusters_deprecation_alert';
import leaveByUrl from '~/namespaces/leave_by_url';
import initVueNotificationsDropdown from '~/notifications';
import initVueStarCount from '~/stars';
import initTerraformNotification from '~/projects/terraform_notification';
import { initUploadFileTrigger } from '~/projects/upload_file';
import initReadMore from '~/read_more';
import initForksButton from '~/forks/init_forks_button';
import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal';
import InitMoreActionsDropdown from '~/groups_projects/init_more_actions_dropdown';
import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
import { initHomePanel } from '../home_panel';
// Project show page loads different overview content based on user preferences
if (document.getElementById('js-tree-list')) {
@ -38,17 +35,14 @@ if (document.querySelector('.project-show-activity')) {
.catch(() => {});
}
initVueNotificationsDropdown();
initVueStarCount();
addShortcutsExtension(ShortcutsNavigation);
initUploadFileTrigger();
initClustersDeprecationAlert();
initTerraformNotification();
initReadMore();
initAmbiguousRefModal();
initHomePanel();
if (document.querySelector('.js-autodevops-banner')) {
import(/* webpackChunkName: 'userCallOut' */ '~/user_callout')
@ -62,8 +56,6 @@ if (document.querySelector('.js-autodevops-banner')) {
.catch(() => {});
}
initForksButton();
InitMoreActionsDropdown();
leaveByUrl('project');
const initCodeDropdown = () => {

View File

@ -31,14 +31,13 @@ const fetchData = (projectPath, path, ref, offset, refType) => {
fetchedBatches.push(offset);
const encodePathFunc = gon.features.encodingLogsTree ? encodeURI : encodeURIComponent;
const url = joinPaths(
gon.relative_url_root || '/',
projectPath,
'/-/refs/',
encodePathFunc(ref),
encodeURI(ref),
'/logs_tree/',
encodePathFunc(removeLeadingSlash(path)),
encodeURI(removeLeadingSlash(path)),
);
return axios

View File

@ -1,40 +0,0 @@
import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '../lib/utils/common_utils';
import StarCount from './components/star_count.vue';
Vue.use(GlToast);
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default () => {
const containers = document.querySelectorAll('.js-vue-star-count');
if (containers.length === 0) {
return false;
}
return containers.forEach((el) => {
const { projectId, starCount, starred, starrersPath, signInPath } = el.dataset;
return new Vue({
el,
provide: {
starred: parseBoolean(starred),
starCount,
projectId,
starrersPath,
signInPath,
},
render(h) {
return h(StarCount);
},
apolloProvider,
});
});
};

View File

@ -30,7 +30,7 @@ export default {
</script>
<template>
<gl-link :href="helpLinks[storageType]" target="_blank" :aria-label="ariaLabel">
<gl-icon name="question-o" :size="12" />
<gl-link :href="helpLinks[storageType]" target="_blank" :aria-label="ariaLabel" class="gl-ml-3">
<gl-icon name="question-o" :size="16" />
</gl-link>
</template>

View File

@ -75,8 +75,7 @@ export default {
try {
const response = await this.$apollo.query({
query: getCurrentUserOrganizationsQuery,
// TODO: implement search support - https://gitlab.com/gitlab-org/gitlab/-/issues/433954.
variables: { after: this.endCursor, first: DEFAULT_PER_PAGE },
variables: { search, after: this.endCursor, first: DEFAULT_PER_PAGE },
});
const { nodes, pageInfo } = response.data.currentUser.organizations;
this.endCursor = pageInfo.endCursor;

View File

@ -1,6 +1,5 @@
export const tdClass =
'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
export const thClass = 'gl-hover-bg-blue-50';
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';

View File

@ -99,7 +99,9 @@ export default {
return participantsQueries[this.issuableType].query;
},
skip() {
return Boolean(participantsQueries[this.issuableType].skipQuery) || !this.isEditing;
return (
Boolean(participantsQueries[this.issuableType].skipQuery) || !this.isEditing || !this.iid
);
},
variables() {
return {

View File

@ -55,26 +55,3 @@ $tooltip-padding-y: 0.5rem;
$tooltip-padding-x: 0.75rem;
$tooltip-arrow-height: 0.5rem;
$tooltip-arrow-width: 1rem;
$b-table-sort-icon-bg-descending: url('data:image/svg+xml, <svg \
xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="4 0 8 16"> \
<path style="fill: #666;" fill-rule="evenodd" d="M11.707085,11.7071 \
L7.999975,15.4142 L4.292875,11.7071 C3.902375,11.3166 3.902375, \
10.6834 4.292875,10.2929 C4.683375,9.90237 \
5.316575,9.90237 5.707075,10.2929 L6.999975, \
11.5858 L6.999975,2 C6.999975,1.44771 \
7.447695,1 7.999975,1 C8.552255,1 8.999975,1.44771 \
8.999975,2 L8.999975,11.5858 L10.292865,10.2929 C10.683395 \
,9.90237 11.316555,9.90237 11.707085,10.2929 \
C12.097605,10.6834 12.097605,11.3166 11.707085,11.7071 Z"/> \
</svg>') !default;
$b-table-sort-icon-bg-ascending: url('data:image/svg+xml,<svg \
xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="4 0 8 16"> \
<path style="fill: #666;" fill-rule="evenodd" d="M4.29289,4.2971 L8,0.59 \
L11.7071,4.2971 C12.0976,4.6876 \
12.0976,5.3208 11.7071,5.7113 C11.3166,6.10183 10.6834, \
6.10183 10.2929,5.7113 L9,4.4184 L9,14.0042 C9,14.55649 \
8.55228,15.0042 8,15.0042 C7.44772,15.0042 7,14.55649 \
7,14.0042 L7,4.4184 L5.70711,5.7113 C5.31658,6.10183 4.68342,6.10183 4.29289,5.7113 \
C3.90237,5.3208 3.90237,4.6876 4.29289,4.2971 Z"/> \
</svg> ') !default;
$b-table-sort-icon-bg-not-sorted: '';

View File

@ -46,7 +46,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:encoding_logs_tree)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end

View File

@ -19,7 +19,6 @@ class Projects::TreeController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:encoding_logs_tree)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end

View File

@ -41,7 +41,6 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:remove_monitor_metrics, @project)
push_frontend_feature_flag(:explain_code_chat, current_user)
push_frontend_feature_flag(:issue_email_participants, @project)
push_frontend_feature_flag(:encoding_logs_tree)
push_frontend_feature_flag(:add_branch_rule, @project)
# TODO: We need to remove the FF eventually when we rollout page_specific_styles
push_frontend_feature_flag(:page_specific_styles, current_user)
@ -196,7 +195,6 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format|
format.html do
@notification_setting = current_user.notification_settings_for(@project) if current_user
@project = @project.present(current_user: current_user)
render_landing_page
end

View File

@ -427,20 +427,21 @@ module ProjectsHelper
def fork_button_data_attributes(project)
return unless current_user
return if project.empty_repo?
if current_user.already_forked?(project) && current_user.forkable_namespaces.size < 2
user_fork_url = namespace_project_path(current_user, current_user.fork_of(project))
end
{
forks_count: project.forks_count,
project_full_path: project.full_path,
project_forks_url: project_forks_path(project),
user_fork_url: user_fork_url,
new_fork_url: new_project_fork_path(project),
can_read_code: can?(current_user, :read_code, project).to_s,
can_create_fork: can?(current_user, :create_fork).to_s,
can_fork_project: can?(current_user, :fork_project, project).to_s,
can_create_fork: can?(current_user, :create_fork).to_s
can_read_code: can?(current_user, :read_code, project).to_s,
forks_count: project.forks_count,
new_fork_url: new_project_fork_path(project),
project_forks_url: project_forks_path(project),
project_full_path: project.full_path,
user_fork_url: user_fork_url
}
end
@ -448,16 +449,48 @@ module ProjectsHelper
starred = current_user ? current_user.starred?(project) : false
{
data: {
project_id: project.id,
sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
star_count: project.star_count,
starred: starred.to_s,
starrers_path: project_starrers_path(project)
}
project_id: project.id,
sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
star_count: project.star_count,
starred: starred.to_s,
starrers_path: project_starrers_path(project)
}
end
def notification_data_attributes(project)
return unless current_user
notification_setting = current_user.notification_settings_for(project)
dropdown_items = notification_dropdown_items(notification_setting).to_json if notification_setting
notification_level = notification_setting.level if notification_setting
{
emails_disabled: project.emails_disabled?.to_s,
notification_dropdown_items: dropdown_items,
notification_help_page_path: help_page_path('user/profile/notifications'),
notification_level: notification_level
}
end
def home_panel_data_attributes
project = @project.is_a?(ProjectPresenter) ? @project.project : @project
dropdown_attributes = groups_projects_more_actions_dropdown_data(project) || {}
fork_button_attributes = fork_button_data_attributes(project) || {}
notification_attributes = notification_data_attributes(project) || {}
star_count_attributes = star_count_data_attributes(project)
{
can_read_project: can?(current_user, :read_project, project).to_s,
is_project_empty: project.empty_repo?.to_s,
project_id: project.id
}.merge(
dropdown_attributes,
fork_button_attributes,
notification_attributes,
star_count_attributes
)
end
def import_from_bitbucket_message
configure_oauth_import_message('Bitbucket', help_page_path("integration/bitbucket"))
end

View File

@ -189,6 +189,10 @@ class BulkImports::Entity < ApplicationRecord
project? ? project&.full_path : group&.full_path
end
def full_path_with_fallback
full_path || Gitlab::Utils.append_path(destination_namespace, destination_slug)
end
def default_visibility_level
return default_group_visibility if group?

View File

@ -1,5 +1,6 @@
- illustration_path = 'illustrations/empty-state/empty-activity-md.svg'
- current_user_empty_message_header = s_('UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!')
- current_user_empty_message_header = s_('UserProfile|No activities found')
- current_user_empty_message_description = s_('UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!')
- primary_button_label = _('New group')
- primary_button_link = new_group_path
- secondary_button_label = _('Explore groups')
@ -11,6 +12,7 @@
- else
= render partial: 'shared/empty_states/profile_tabs', locals: { illustration_path: illustration_path,
current_user_empty_message_header: current_user_empty_message_header,
current_user_empty_message_description: current_user_empty_message_description,
primary_button_label: primary_button_label,
primary_button_link: primary_button_link,
secondary_button_label: secondary_button_label,

View File

@ -28,7 +28,7 @@
= render Pajamas::ButtonComponent.new(href: new_project_path(namespace_id: @group.id), variant: :confirm, button_options: { data: { testid: 'new-project-button' }, class: 'gl-sm-w-auto gl-w-full' }) do
= _('New project')
= render 'shared/groups_projects_more_actions_dropdown', source: @group
= render 'groups/more_actions_dropdown', source: @group
- if @group.description.present?
.group-home-desc.mt-1

View File

@ -6,11 +6,5 @@
%span.gl-sr-only{ itemprop: 'identifier', data: { testid: 'group-id-content' } }
= s_('GroupPage|Group ID: %{id}') % { id: id }
- elsif can?(current_user, :read_project, @project)
- id = @project.id
%span.gl-sr-only{ itemprop: 'identifier', data: { testid: 'project-id-content' } }
= s_('ProjectPage|Project ID: %{id}') % { id: id }
- if id || current_user
.js-groups-projects-more-actions-dropdown{ data: dropdown_data }

View File

@ -1,8 +1,7 @@
- add_to_breadcrumbs _('New group'), new_group_path
- add_to_breadcrumbs _('Import group'), new_group_path(anchor: 'import-group-pane')
- add_to_breadcrumbs s_('BulkImport|Direct transfer history'), history_import_bulk_imports_path
- if params[:id].present?
- add_to_breadcrumbs params[:id], history_import_bulk_import_path(id: params[:id])
- page_title format(s_('Import|Failures for %{id}'), id: params[:entity_id])
- add_to_breadcrumbs @bulk_import.id, history_import_bulk_import_path(@bulk_import.id)
- page_title format(s_('Import|Failures for %{id}'), id: @bulk_import_entity.full_path_with_fallback)
.js-bulk-import-details{ data: { id: params[:id], entity_id: params[:entity_id] } }
.js-bulk-import-details{ data: { id: @bulk_import.id, entity_id: @bulk_import_entity.id, full_path: @bulk_import_entity.full_path_with_fallback } }

View File

@ -1,5 +1,4 @@
- empty_repo = @project.empty_repo?
- emails_disabled = @project.emails_disabled?
- ff_reorg_disabled = Feature.disabled?(:project_overview_reorg)
%header.project-home-panel.js-show-on-project-root.gl-mt-5{ class: [("empty-project" if empty_repo)] }
@ -19,12 +18,8 @@
- if current_user
- if current_user.admin?
= link_button_to nil, [:admin, @project], icon: 'admin', title: _('View project in admin area'), data: {toggle: 'tooltip', placement: 'top', container: 'body'}
- if @notification_setting
.js-vue-notification-dropdown{ data: { disabled: emails_disabled.to_s, dropdown_items: notification_dropdown_items(@notification_setting).to_json, notification_level: @notification_setting.level, help_page_path: help_page_path('user/profile/notifications'), project_id: @project.id, no_flip: 'true' } }
= render 'projects/buttons/star', project: @project
= render 'projects/buttons/fork'
= render 'shared/groups_projects_more_actions_dropdown', source: @project
#js-home-panel{ data: home_panel_data_attributes }
- if ff_reorg_disabled
- if can?(current_user, :read_code, @project)

View File

@ -1,3 +0,0 @@
- unless @project.empty_repo?
- if current_user
#js-forks-button{ data: fork_button_data_attributes(@project) }

View File

@ -1 +0,0 @@
.js-vue-star-count{ star_count_data_attributes(@project) }

View File

@ -1,21 +1,23 @@
- current_user_empty_message_description = local_assigns.fetch(:current_user_empty_message_description, nil)
- secondary_button_link = local_assigns.fetch(:secondary_button_link, nil)
- secondary_button_label = local_assigns.fetch(:secondary_button_label, nil)
- primary_button_link = local_assigns.fetch(:primary_button_link, nil)
- primary_button_label = local_assigns.fetch(:primary_button_label, nil)
- is_current_user = user_profile? && current_user.present? && current_user.username == params[:username]
.nothing-here-block
.svg-content
= image_tag illustration_path, size: '75'
.text-content
- if user_profile? && current_user.present? && current_user.username == params[:username]
%h5= current_user_empty_message_header
- if is_current_user
= render Pajamas::EmptyStateComponent.new(svg_path: illustration_path,
title: current_user_empty_message_header,
primary_button_text: primary_button_label,
primary_button_link: primary_button_link,
secondary_button_text: secondary_button_label,
secondary_button_link: secondary_button_link) do |c|
- c.with_description do
- if current_user_empty_message_description.present?
%p= current_user_empty_message_description
- if primary_button_link.present?
= link_button_to primary_button_label, primary_button_link, variant: :confirm
- if secondary_button_link.present?
= link_button_to secondary_button_label, secondary_button_link, variant: :confirm, category: :secondary
- else
%h5= visitor_empty_message
= current_user_empty_message_description
- else
= render Pajamas::EmptyStateComponent.new(svg_path: illustration_path,
title: visitor_empty_message)

View File

@ -1,5 +1,5 @@
- illustration_path = 'illustrations/empty-state/empty-groups-md.svg'
- current_user_empty_message_header = s_('UserProfile|You can create a group for several dependent projects.')
- current_user_empty_message_header = s_('UserProfile|You can create a group for several dependent projects')
- current_user_empty_message_description = s_('UserProfile|Groups are the best way to manage projects and members.')
- primary_button_label = _('New group')
- primary_button_link = new_group_path

View File

@ -12,16 +12,16 @@
- compact_mode = false unless local_assigns[:compact_mode] == true
- card_mode = local_assigns[:card_mode] == true
- css_classes = "#{'compact' if compact_mode} #{'explore' if explore_projects_tab?}"
- contributed_projects_current_user_empty_message_header = s_('UserProfile|Explore public groups to find projects to contribute to.')
- contributed_projects_current_user_empty_message_header = s_('UserProfile|Explore public groups to find projects to contribute to')
- contributed_projects_visitor_empty_message = s_('UserProfile|This user hasn\'t contributed to any projects')
- starred_projects_illustration_path = 'illustrations/empty-state/empty-projects-starred-md.svg'
- starred_projects_current_user_empty_message_header = s_('UserProfile|Star projects to track their progress and show your appreciation.')
- starred_projects_current_user_empty_message_header = s_('UserProfile|Star projects to track their progress and show your appreciation')
- starred_projects_visitor_empty_message = s_('UserProfile|This user hasn\'t starred any projects')
- own_projects_illustration_path = 'illustrations/empty-state/empty-projects-md.svg'
- own_projects_current_user_empty_message_header = s_('UserProfile|You haven\'t created any personal projects.')
- own_projects_current_user_empty_message_header = s_('UserProfile|You haven\'t created any personal projects')
- own_projects_current_user_empty_message_description = s_('UserProfile|Your projects can be available publicly, internally, or privately, at your choice.')
- own_projects_visitor_empty_message = s_('UserProfile|There are no projects available to be displayed here.')
- explore_page_empty_message = s_('UserProfile|Explore public groups to find projects to contribute to.')
- own_projects_visitor_empty_message = s_('UserProfile|There are no projects available to be displayed here')
- explore_page_empty_message = s_('UserProfile|Explore public groups to find projects to contribute to')
- new_project_button_label = _('New project')
- new_project_button_link = new_project_path
- explore_projects_button_label = _('Explore projects')

View File

@ -1,9 +1,9 @@
- followers_illustration_path = 'illustrations/empty-state/empty-friends-md.svg'
- followers_visitor_empty_message = s_('UserProfile|This user doesn\'t have any followers.')
- followers_current_user_empty_message_header = s_('UserProfile|You do not have any followers.')
- followers_visitor_empty_message = s_('UserProfile|This user doesn\'t have any followers')
- followers_current_user_empty_message_header = s_('UserProfile|You do not have any followers')
- following_illustration_path = 'illustrations/empty-state/empty-friends-md.svg'
- following_visitor_empty_message = s_('UserProfile|This user isn\'t following other users.')
- following_current_user_empty_message_header = s_('UserProfile|You are not following other users.')
- following_visitor_empty_message = s_('UserProfile|This user isn\'t following other users')
- following_current_user_empty_message_header = s_('UserProfile|You are not following other users')
- if users.size > 0
.row.gl-mt-3

View File

@ -1,10 +1,10 @@
- link_project = local_assigns.fetch(:link_project, false)
- illustration_path = 'illustrations/empty-state/empty-snippets-md.svg'
- current_user_empty_message_header = s_('UserProfile|You haven\'t created any snippets.')
- current_user_empty_message_header = s_('UserProfile|You haven\'t created any snippets')
- current_user_empty_message_description = s_('UserProfile|Snippets in GitLab can either be private, internal, or public.')
- primary_button_label = _('New snippet')
- primary_button_link = new_snippet_path if can?(current_user, :create_snippet)
- visitor_empty_message = s_('UserProfile|No snippets found.')
- visitor_empty_message = s_('UserProfile|No snippets found')
.snippets-list-holder
%ul.content-list

View File

@ -1,8 +0,0 @@
---
name: encoding_logs_tree
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136323
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/432559
milestone: '16.7'
type: development
group: group::source code
default_enabled: false

View File

@ -789,6 +789,8 @@
- 1
- - work_items_update_parent_objectives_progress
- 1
- - work_items_validate_epic_work_item_sync
- 1
- - x509_certificate_revoke
- 1
- - zoekt_indexer

View File

@ -16500,6 +16500,7 @@ Options for runner Google Cloud provisioning.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="cirunnergooglecloudprovisioningoptionsprojectsetupshellscript"></a>`projectSetupShellScript` | [`String`](#string) | Instructions for setting up a Google Cloud project. |
| <a id="cirunnergooglecloudprovisioningoptionsregions"></a>`regions` | [`CiRunnerCloudProvisioningRegionConnection`](#cirunnercloudprovisioningregionconnection) | Regions available for provisioning a runner. (see [Connections](#connections)) |
#### Fields with arguments
@ -26344,7 +26345,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
##### `Project.runnerCloudProvisioningOptions`
Options for provisioning the runner on Google Cloud. Returns `null` if `:google_cloud_runner_provisioning` feature flag is disabled, or the GitLab instance is not a SaaS instance.
Options for provisioning the runner on a cloud provider. Returns `null` if `:google_cloud_runner_provisioning` feature flag is disabled, or the GitLab instance is not a SaaS instance.
NOTE:
**Introduced** in 16.9.

View File

@ -22,20 +22,22 @@ To update the documentation:
1. Go to the [GitLab community fork](https://gitlab.com/gitlab-community/gitlab) or your own fork.
1. Find the documentation page in the `\doc` directory.
1. If you know Git, make your changes and open a merge request.
If not, follow these steps:
1. In the upper right, select **Edit > Edit single file**.
1. Make your changes.
1. When you're ready to submit your changes, in the **Commit message** text box, enter a commit message.
Use 3-5 words, start with a capital letter, and do not end with a period.
1. Select **Commit changes**.
1. In the upper right, select **Edit > Edit single file**.
1. Make your changes.
1. When you're ready to submit your changes, in the **Commit message** text box, enter a commit message.
Use 3-5 words, start with a capital letter, and do not end with a period.
1. Select **Commit changes**.
1. If you're working from the community fork, a new merge request opens and you can continue to the next step.
If you're working from your own fork, first do the following:
1. On the left sidebar, select **Code > Merge requests**.
1. Select **New merge request**.
1. For the source branch, select your fork and branch. If you did not create a branch, select `master`.
For the target branch, select the [GitLab repository](https://gitlab.com/gitlab-org/gitlab) `master` branch.
1. Select **Compare branches and continue**. A new merge request opens.
1. Select the **Documentation** template. In the description, write a brief summary of the changes and link to the related issue, if there is one.
1. Select **Create merge request**.
1. On the **New merge request** page, select the **Documentation** template and select **Apply template**.
1. In the description, write a brief summary of the changes and link to the related issue, if there is one.
1. Select **Create merge request**.
1. After your merge request is created, look for a message from **GitLab Bot**. This message has instructions for what to do when you're ready for review.
Alternatively, if you don't want to search through the `/doc` directory, on <https://docs.gitlab.com>, at the bottom of any page, select **View page source** or **Edit in Web IDE**.
You are prompted to create a fork or switch to your fork before you can make changes.

View File

@ -82,6 +82,11 @@ planned for release in 16.9.1.
directly to 16.8.2, which [restores compatibility with Redis 6.0](https://gitlab.com/gitlab-org/gitlab/-/issues/439418).
- NOTE: You should upgrade to Redis 6.2 or later as [Redis 6.0 is no longer supported](https://endoflife.date/redis).
- Backups in environments that have PgBouncer must [bypass PgBouncer by setting variables that are prefixed with `GITLAB_BACKUP_`](../../administration/backup_restore/backup_gitlab.md#bypassing-pgbouncer). But due to an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/422163), `gitlab-backup` uses the regular database connection through PgBouncer instead of the direct connection defined in the override, and the database backup fails. The workaround is to use `pg_dump` directly.
- Affected releases: 15.11.x - 16.8.x
- Fixed in: 16.9
### Geo installations
- PostgreSQL version 14 is the default for fresh installations of GitLab 16.7 and later. Due to a known issue, existing Geo secondary

View File

@ -308,7 +308,7 @@ in the hierarchy.
To ensure that the user cap applies when groups, subgroups, or projects are shared externally, restrict group sharing only within the top-level namespace. This ensure that groups in the same top-leve namespace can be invited, and prevents the addition of new users (seats) when the group is shared.
User cap doesnt consider whether users are billable or not (e.g., Free Guest Users in Ultimate). In other words, if you set a cap of 500, user caps block new sign-ups after 500 users, regardless of whether those are all consuming paid seats or not.
On GitLab.com, on the Ultimate tier, there is a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/441504) where you cannot add new guest users to a group when the amount of billable users exceeds the user cap. For example, suppose you have a user cap of 5, with 3 developers and 2 guests. After you add 2 more developers, you cannot add any more users, even if they are guest users that don't consume a billable seat.
## Group file templates

View File

@ -200,8 +200,6 @@ DETAILS:
**Tier:** Premium, Ultimate
**Offering:** SaaS, self-managed
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/440) in GitLab 8.9.
This process allows you to lock one file at a time through the GitLab UI and
requires access to the [GitLab Premium or Ultimate tier](https://about.gitlab.com/pricing/).

View File

@ -10,8 +10,6 @@ DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** SaaS, self-managed
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3619) in GitLab 13.6.
Export all the data collected from a project's merge requests into a comma-separated values (CSV) file.
To export merge requests to a CSV file:

View File

@ -55,15 +55,23 @@ For more information, see [Data usage in GitLab Duo Suggested Reviewers](data_us
### Enable Suggested Reviewers
Project Maintainers or Owners can enable Suggested Reviewers by visiting
the [project settings](../../settings/index.md).
Enabling Suggested Reviewers triggers GitLab to create an ML model for your
project that is used to generate reviewers. The larger your project, the longer
this process can take. Usually, the model is ready to generate suggestions
within a few hours.
No action is required after the feature is enabled. After the model is ready,
Prerequisites:
- You have the Owner or Maintainer role in the project.
To do this:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Scroll to **Suggested reviewers**, and select **Enable suggested reviewers**.
1. Select **Save changes**.
After you enable the feature, no additional action is needed. After the model is ready,
recommendations populate the **Reviewer** dropdown list in the right-hand sidebar
of a merge request with new commits.
@ -112,8 +120,6 @@ DETAILS:
**Tier:** Premium, Ultimate
**Offering:** SaaS, self-managed
> - Moved to GitLab Premium in 13.9.
To assign multiple reviewers to a merge request, in a text area in
the merge request, use the `/assign_reviewer @user`
[quick action](../../quick_actions.md#issues-merge-requests-and-epics). Alternatively:

View File

@ -46,7 +46,9 @@ Prerequisites:
To do this:
1. Go to the merge request and select **Edit**.
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Select **Edit**.
1. Select or clear the **Squash commits when merge request is accepted** checkbox.
1. Select **Save changes**.
@ -55,8 +57,9 @@ To do this:
If your project allows you to select squashing options for merge requests, to
squash the commits as part of the merge process:
1. Go to the merge request, and scroll to the merge request reports section that
contains the **Merge** button.
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Scroll to the merge request reports section that contains the **Merge** button.
1. Ensure the **Squash commits** checkbox is selected. This checkbox doesn't display
if the project's squashing option is set to either **Do not allow** or **Require**.
1. Optional. To modify either the squash commit message or the merge commit message
@ -65,10 +68,6 @@ squash the commits as part of the merge process:
## Configure squash options for a project
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17613) in GitLab 13.2 [with a flag](../../../administration/feature_flags.md) named `squash_options`, disabled by default.
> - [Enabled on GitLab.com and self-managed by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39382) in GitLab 13.3.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/232536) in GitLab 13.8. Feature flag `squash_options` removed.
Prerequisites:
- You must have at least the Maintainer role for this project.

View File

@ -80,7 +80,8 @@ using the API. You don't need to wait for a merge request webhook payload to be
Within each project's settings, you can see a list of status check services added to the project:
1. In your project, go to **Settings > Merge requests** section.
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Settings > Merge requests**.
1. Scroll down to **Status checks**.
![Status checks list](img/status_checks_list_view_v14_0.png)
@ -121,8 +122,8 @@ The name **has** to be unique for the project.
#### API to check
This field requires a URL and **must** use either the HTTP or HTTPs protocols.
We **recommend** using HTTPs to protect your merge request data in transit.
This field requires a URL and **must** use either the HTTP or HTTPS protocols.
We **recommend** using HTTPS to protect your merge request data in transit.
The URL **must** be set and **must** be unique for the project.
#### Target branch
@ -170,7 +171,9 @@ When there are pending status checks, the widget polls for updates every few sec
To retry a failed status check:
1. Expand the merge request widget to show the list of external status checks.
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Merge requests** and find your merge request.
1. Scroll to the merge request reports section, and expand the dropdown list to show the list of external status checks.
1. Select **Retry** (**{retry}**) on the failed external status check row. The status check is put back into a pending state.
An organization might have a policy that does not allow merging merge requests if

View File

@ -78,7 +78,6 @@ module Gitlab
push_frontend_feature_flag(:ui_for_organizations, current_user)
# To be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/399248
push_frontend_feature_flag(:remove_monitor_metrics)
push_frontend_feature_flag(:encoding_logs_tree)
push_frontend_feature_flag(:group_user_saml)
end

View File

@ -5802,6 +5802,9 @@ msgstr ""
msgid "Analytics|Visualization was saved successfully"
msgstr ""
msgid "Analytics|Would you like to replace your existing selection with a new visualization generated through GitLab Duo?"
msgstr ""
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@ -13765,6 +13768,9 @@ msgstr ""
msgid "Continue to the next step"
msgstr ""
msgid "Continue with GitLab Duo"
msgstr ""
msgid "Continue with overages"
msgstr ""
@ -13864,9 +13870,15 @@ msgstr ""
msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
msgstr ""
msgid "ContributionAnalytics|This page sources data from the %{link_start}analytical database ClickHouse%{link_end}, with a few minutes of delay."
msgstr ""
msgid "ContributionAnalytics|Total Contributions"
msgstr ""
msgid "ContributionAnalytics|Using ClickHouse"
msgstr ""
msgid "ContributionEvent|Accepted merge request %{targetLink} in %{resourceParentLink}."
msgstr ""
@ -35381,6 +35393,9 @@ msgstr ""
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
msgid "PackageRegistry|Published to the %{project} Terraform Module Registry %{datetime}"
msgstr ""
msgid "PackageRegistry|Push protected up to access level"
msgstr ""
@ -54257,7 +54272,7 @@ msgstr ""
msgid "UserProfile|Edit profile"
msgstr ""
msgid "UserProfile|Explore public groups to find projects to contribute to."
msgid "UserProfile|Explore public groups to find projects to contribute to"
msgstr ""
msgid "UserProfile|Failed to set avatar. Please reload the page to try again."
@ -54284,7 +54299,10 @@ msgstr ""
msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!"
msgstr ""
msgid "UserProfile|No snippets found."
msgid "UserProfile|No activities found"
msgstr ""
msgid "UserProfile|No snippets found"
msgstr ""
msgid "UserProfile|Overview"
@ -54308,7 +54326,7 @@ msgstr ""
msgid "UserProfile|Snippets in GitLab can either be private, internal, or public."
msgstr ""
msgid "UserProfile|Star projects to track their progress and show your appreciation."
msgid "UserProfile|Star projects to track their progress and show your appreciation"
msgstr ""
msgid "UserProfile|Starred projects"
@ -54320,15 +54338,12 @@ msgstr ""
msgid "UserProfile|Subscribe"
msgstr ""
msgid "UserProfile|There are no projects available to be displayed here."
msgid "UserProfile|There are no projects available to be displayed here"
msgstr ""
msgid "UserProfile|This user doesn't have any followers"
msgstr ""
msgid "UserProfile|This user doesn't have any followers."
msgstr ""
msgid "UserProfile|This user doesn't have any snippets"
msgstr ""
@ -54347,9 +54362,6 @@ msgstr ""
msgid "UserProfile|This user isn't following other users"
msgstr ""
msgid "UserProfile|This user isn't following other users."
msgstr ""
msgid "UserProfile|Unconfirmed user"
msgstr ""
@ -54374,22 +54386,16 @@ msgstr ""
msgid "UserProfile|You are not following other users"
msgstr ""
msgid "UserProfile|You are not following other users."
msgstr ""
msgid "UserProfile|You can create a group for several dependent projects."
msgid "UserProfile|You can create a group for several dependent projects"
msgstr ""
msgid "UserProfile|You do not have any followers"
msgstr ""
msgid "UserProfile|You do not have any followers."
msgid "UserProfile|You haven't created any personal projects"
msgstr ""
msgid "UserProfile|You haven't created any personal projects."
msgstr ""
msgid "UserProfile|You haven't created any snippets."
msgid "UserProfile|You haven't created any snippets"
msgstr ""
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."

View File

@ -62,7 +62,7 @@
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/fonts": "^1.3.0",
"@gitlab/svgs": "3.84.0",
"@gitlab/ui": "^74.9.1",
"@gitlab/ui": "^74.9.3",
"@gitlab/visual-review-tools": "1.7.3",
"@gitlab/web-ide": "^0.0.1-dev-20240214084918",
"@mattiasbuelens/web-streams-adapter": "^0.1.0",

View File

@ -173,40 +173,11 @@ RSpec.describe ProjectsController, feature_category: :groups_and_projects do
sign_in(user)
end
context "user does not have access to project" do
let(:private_project) { create(:project, :private) }
it "does not initialize notification setting" do
get :show, params: { namespace_id: private_project.namespace, id: private_project }
expect(assigns(:notification_setting)).to be_nil
end
end
context "user has access to project" do
before do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
end
context "and does not have notification setting" do
it "initializes notification as disabled" do
get :show, params: { namespace_id: public_project.namespace, id: public_project }
expect(assigns(:notification_setting).level).to eq("global")
end
end
context "and has notification setting" do
before do
setting = user.notification_settings_for(public_project)
setting.level = :watch
setting.save!
end
it "shows current notification setting" do
get :show, params: { namespace_id: public_project.namespace, id: public_project }
expect(assigns(:notification_setting).level).to eq("watch")
end
end
context 'when ambiguous_ref_modal is disabled' do
before do
stub_feature_flags(ambiguous_ref_modal: false)

View File

@ -66,7 +66,7 @@ RSpec.describe 'Dashboard shortcuts', :js, feature_category: :shared do
find('body').send_keys([:shift, 'P'])
find('.nothing-here-block')
expect(page).to have_content('Explore public groups to find projects to contribute to.')
expect(page).to have_content('Explore public groups to find projects to contribute to')
end
end

View File

@ -40,7 +40,7 @@ RSpec.describe 'Dashboard > User filters projects', feature_category: :groups_an
it 'returns message when starred projects fitler returns no results' do
fill_in 'project-filter-form-field', with: 'Beta\n'
expect(page).to have_content('There are no projects available to be displayed here.')
expect(page).to have_content('There are no projects available to be displayed here')
expect(page).not_to have_content('You don\'t have starred projects yet')
end
end

View File

@ -82,7 +82,7 @@ RSpec.describe 'User explores projects', feature_category: :user_profile do
it 'shows correct empty state message', :js do
fill_in 'name', with: 'zzzzzzzzzzzzzzzzzzz'
expect(page).to have_content('Explore public groups to find projects to contribute to.')
expect(page).to have_content('Explore public groups to find projects to contribute to')
end
end
@ -133,7 +133,7 @@ RSpec.describe 'User explores projects', feature_category: :user_profile do
context 'when there are no projects' do
shared_examples 'explore page empty state' do
it 'shows correct empty state message' do
expect(page).to have_content('Explore public groups to find projects to contribute to.')
expect(page).to have_content('Explore public groups to find projects to contribute to')
end
end

View File

@ -42,7 +42,7 @@ RSpec.describe 'Topic show page', feature_category: :groups_and_projects do
context 'without associated projects' do
it 'shows correct empty state message' do
expect(page).to have_content('Explore public groups to find projects to contribute to.')
expect(page).to have_content('Explore public groups to find projects to contribute to')
end
end
end

View File

@ -100,7 +100,7 @@ describe('~/access_tokens/components/access_token_table_app', () => {
__('Token name'),
__('Scopes'),
s__('AccessTokens|Created'),
__('Last Used'),
'Last Used The last time a token was used',
__('Expires'),
__('Action'),
]);
@ -114,7 +114,7 @@ describe('~/access_tokens/components/access_token_table_app', () => {
__('Token name'),
__('Scopes'),
s__('AccessTokens|Created'),
__('Last Used'),
'Last Used The last time a token was used',
__('Expires'),
__('Role'),
__('Action'),
@ -192,7 +192,7 @@ describe('~/access_tokens/components/access_token_table_app', () => {
__('Token name'),
__('Scopes'),
s__('AccessTokens|Created'),
__('Last Used'),
'Last Used The last time a token was used',
__('Expires'),
__('Role'),
].forEach((text, index) => {

View File

@ -1,4 +1,4 @@
import { GlTable, GlAlert, GlLoadingIcon, GlDropdown, GlIcon, GlAvatar, GlLink } from '@gitlab/ui';
import { GlTable, GlAlert, GlLoadingIcon, GlDropdown, GlAvatar, GlLink } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
@ -174,7 +174,7 @@ describe('AlertManagementTable', () => {
await nextTick();
expect(wrapper.findComponent(GlTable).exists()).toBe(true);
expect(findAlertsTable().findComponent(GlIcon).classes('icon-critical')).toBe(true);
expect(findAlertsTable().find('[data-testid="severity-critical-icon"]').exists()).toBe(true);
});
it('renders severity text', () => {

View File

@ -26,7 +26,7 @@ describe('behaviors/markdown/render_json_table', () => {
const TEST_LABELS = TEST_DATA.fields.map((x) => x.label);
const tableAsData = (table) => ({
head: Array.from(table.querySelectorAll('thead th')).map((td) => td.textContent),
head: Array.from(table.querySelectorAll('thead th')).map((td) => td.textContent.trim()),
body: Array.from(table.querySelectorAll('tbody > tr')).map((tr) =>
Array.from(tr.querySelectorAll('td')).map((x) => x.textContent),
),

View File

@ -46,7 +46,7 @@ describe('Ci variable table', () => {
wrapper.findAllByTestId('ci-variable-table-row-attributes').at(rowIndex);
const findAttributeByIndex = (rowIndex, attributeIndex) =>
findAttributesRow(rowIndex).findAllComponents(GlBadge).at(attributeIndex).text();
const findTableColumnText = (index) => wrapper.findAll('th').at(index).text();
const findTableColumnText = (index) => wrapper.findAll('th > div').at(index).text();
const findVariableRow = (rowIndex) =>
wrapper.findAllByTestId('ci-variable-table-row-variable').at(rowIndex);
const findGroupCiCdSettingsLink = (rowIndex) =>
@ -105,7 +105,7 @@ describe('Ci variable table', () => {
// last column is for the edit button, which has no text
it.each`
index | text
${0} | ${'Key (Click to sort descending)'}
${0} | ${'Key'}
${1} | ${'Value'}
${2} | ${'Environments'}
${3} | ${'Actions'}

View File

@ -13,7 +13,7 @@ describe('moreActionsDropdown', () => {
wrapper = shallowMountExtended(moreActionsDropdown, {
provide: {
isGroup: false,
id: 1,
groupOrProjectId: 1,
leavePath: '',
leaveConfirmMessage: '',
withdrawPath: '',
@ -39,7 +39,7 @@ describe('moreActionsDropdown', () => {
beforeEach(async () => {
createComponent({
provideData: {
id: 22,
groupOrProjectId: 22,
},
});
await showDropdown();
@ -60,7 +60,7 @@ describe('moreActionsDropdown', () => {
createComponent({
provideData: {
isGroup: true,
id: 11,
groupOrProjectId: 11,
},
});
await showDropdown();

View File

@ -0,0 +1,65 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import HomePanel from '~/pages/projects/home_panel/components/home_panel.vue';
import ForksButton from '~/forks/components/forks_button.vue';
import MoreActionsDropdown from '~/groups_projects/components/more_actions_dropdown.vue';
import NotificationsDropdown from '~/notifications/components/notifications_dropdown.vue';
import StarCount from '~/stars/components/star_count.vue';
describe('HomePanel', () => {
let wrapper;
const createComponent = ({ isLoggedIn = false, provide = {} } = {}) => {
if (isLoggedIn) {
window.gon.current_user_id = 1;
}
wrapper = shallowMountExtended(HomePanel, {
provide: {
...provide,
},
});
};
const findForksButton = () => wrapper.findComponent(ForksButton);
const findMoreActionsDropdown = () => wrapper.findComponent(MoreActionsDropdown);
const findNotificationsDropdown = () => wrapper.findComponent(NotificationsDropdown);
const findStarCount = () => wrapper.findComponent(StarCount);
describe.each`
isLoggedIn | canReadProject | isProjectEmpty | isForkButtonVisible | isMoreActionsDropdownVisible | isNotificationDropdownVisible | isStarCountVisible
${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true}
${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true}
${true} | ${false} | ${true} | ${false} | ${true} | ${false} | ${true}
${true} | ${false} | ${false} | ${false} | ${true} | ${false} | ${true}
${false} | ${true} | ${true} | ${false} | ${true} | ${false} | ${true}
${false} | ${true} | ${false} | ${false} | ${true} | ${false} | ${true}
${false} | ${false} | ${true} | ${false} | ${true} | ${false} | ${true}
${false} | ${false} | ${false} | ${false} | ${true} | ${false} | ${true}
`(
'renders components',
({
isLoggedIn,
canReadProject,
isProjectEmpty,
isForkButtonVisible,
isMoreActionsDropdownVisible,
isNotificationDropdownVisible,
isStarCountVisible,
}) => {
it('as expected', () => {
createComponent({
isLoggedIn,
provide: {
canReadProject,
isProjectEmpty,
},
});
expect(findForksButton().exists()).toBe(isForkButtonVisible);
expect(findMoreActionsDropdown().exists()).toBe(isMoreActionsDropdownVisible);
expect(findNotificationsDropdown().exists()).toBe(isNotificationDropdownVisible);
expect(findStarCount().exists()).toBe(isStarCountVisible);
});
},
);
});

View File

@ -15,9 +15,12 @@ describe('Bulk import details app', () => {
entityId: mockEntityId,
};
const createComponent = () => {
const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(BulkImportDetailsApp, {
propsData: { ...defaultProps },
propsData: {
...defaultProps,
...props,
},
});
};
@ -32,6 +35,20 @@ describe('Bulk import details app', () => {
expect(headingText).toBe(`Items that failed to be imported for ${mockEntityId}`);
});
it('renders heading with fullPath when provided', () => {
const mockFullPath = 'full/path';
createComponent({
props: {
fullPath: mockFullPath,
},
});
const headingText = wrapper.find('h1').text();
expect(headingText).toBe(`Items that failed to be imported for ${mockFullPath}`);
});
it('renders import table', () => {
createComponent();

View File

@ -118,7 +118,9 @@ describe('MembersTable', () => {
tableFields: [field],
});
expect(wrapper.findByText(label, { selector: '[role="columnheader"]' }).exists()).toBe(true);
expect(wrapper.findByText(label, { selector: '[role="columnheader"] > div' }).exists()).toBe(
true,
);
if (expectedComponent) {
expect(

View File

@ -60,7 +60,7 @@ describe('Package History', () => {
${'created-on'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'clock'} | ${'Test package version 1.0.0 was first created'} | ${mavenPackage.created_at} | ${null}
${'first-pipeline-commit'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'commit'} | ${'Created by commit sha-baz on branch branch-name'} | ${null} | ${mockPipelineInfo.project.commit_url}
${'first-pipeline-pipeline'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pipeline'} | ${'Built by pipeline #1 triggered by foo'} | ${mockPipelineInfo.created_at} | ${mockPipelineInfo.project.pipeline_url}
${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Package Registry'} | ${mavenPackage.created_at} | ${null}
${'published'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'package'} | ${'Published to the baz project Terraform Module Registry'} | ${mavenPackage.created_at} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'history'} | ${'Package has 1 archived update'} | ${null} | ${null}
${'archived'} | ${HISTORY_PIPELINES_LIMIT + 3} | ${'history'} | ${'Package has 2 archived updates'} | ${null} | ${null}
${'pipeline-entry'} | ${HISTORY_PIPELINES_LIMIT + 2} | ${'pencil'} | ${'Package updated by commit sha-baz on branch branch-name, built by pipeline #3, and published to the registry'} | ${mavenPackage.created_at} | ${mockPipelineInfo.project.commit_url}

View File

@ -23,8 +23,8 @@ describe('FollowersTab', () => {
loading: false,
page: 1,
totalItems: 50,
currentUserEmptyStateTitle: 'UserProfile|You do not have any followers.',
visitorEmptyStateTitle: "UserProfile|This user doesn't have any followers.",
currentUserEmptyStateTitle: 'UserProfile|You do not have any followers',
visitorEmptyStateTitle: "UserProfile|This user doesn't have any followers",
};
const defaultProvide = {

View File

@ -14,7 +14,6 @@ describe('commits service', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
window.gon.features = { encodingLogsTree: true };
mock.onGet(url).reply(HTTP_STATUS_OK, [], {});
jest.spyOn(axios, 'get');
@ -56,19 +55,6 @@ describe('commits service', () => {
expect(axios.get).toHaveBeenCalledWith(encodedUrl, expect.anything());
});
describe('when encodingLogsTree FF is off', () => {
beforeEach(() => {
window.gon.features = {};
});
it('encodes the path and ref with encodeURIComponent', async () => {
const encodedRef = encodeURIComponent(refWithSpecialCharMock);
const encodedUrl = `/some-project/-/refs/${encodedRef}/logs_tree/with%20%24peci%40l%20ch%40rs%2F`;
await requestCommits(1, 'some-project', 'with $peci@l ch@rs/', refWithSpecialCharMock);
expect(axios.get).toHaveBeenCalledWith(encodedUrl, expect.anything());
});
});
it('calls axios get once per batch', async () => {
await Promise.all([requestCommits(0), requestCommits(1), requestCommits(23)]);

View File

@ -177,6 +177,7 @@ describe('OrganizationSelect', () => {
it('calls graphQL query correct `after` variable', () => {
expect(getCurrentUserOrganizationsQueryMultiplePagesHandler).toHaveBeenCalledWith({
search: '',
after: pageInfo.endCursor,
first: DEFAULT_PER_PAGE,
});
@ -184,6 +185,26 @@ describe('OrganizationSelect', () => {
});
});
describe('when listbox is searched', () => {
const searchTerm = 'foo';
beforeEach(async () => {
createComponent();
openListbox();
await waitForPromises();
findListbox().vm.$emit('search', searchTerm);
});
it('calls graphQL query with search term', () => {
expect(getCurrentUserOrganizationsQueryHandler).toHaveBeenCalledWith({
search: searchTerm,
after: null,
first: DEFAULT_PER_PAGE,
});
});
});
it('shows an error when fetching organizations fails', async () => {
createComponent({
handlers: [[getCurrentUserOrganizationsQuery, jest.fn().mockRejectedValueOnce()]],

View File

@ -131,6 +131,12 @@ describe('User select dropdown', () => {
expect(participantsQueryHandlerSuccess).not.toHaveBeenCalled();
});
it('skips the participant query if `iid` is not defined', () => {
createComponent({ props: { iid: null } });
expect(participantsQueryHandlerSuccess).not.toHaveBeenCalled();
});
it('emits an `error` event if participants query was rejected', async () => {
createComponent({ participantsQueryHandler: mockError });
await waitForPromises();

View File

@ -1078,6 +1078,124 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
end
end
describe '#star_count_data_attributes' do
before do
allow(user).to receive(:starred?).with(project).and_return(starred)
allow(helper).to receive(:new_session_path).and_return(sign_in_path)
allow(project).to receive(:star_count).and_return(5)
end
let(:sign_in_path) { 'sign/in/path' }
let(:common_data_attributes) do
{
project_id: project.id,
sign_in_path: sign_in_path,
star_count: 5,
starrers_path: "/#{project.full_path}/-/starrers"
}
end
subject { helper.star_count_data_attributes(project) }
context 'when user has already starred the project' do
let(:starred) { true }
let(:expected) { common_data_attributes.merge({ starred: "true" }) }
it { is_expected.to eq(expected) }
end
context 'when user has not starred the project' do
let(:starred) { false }
let(:expected) { common_data_attributes.merge({ starred: "false" }) }
it { is_expected.to eq(expected) }
end
end
describe '#notification_data_attributes' do
before do
allow(helper).to receive(:help_page_path).and_return(notification_help_path)
allow(project).to receive(:emails_disabled?).and_return(false)
end
let(:notification_help_path) { 'notification/help/path' }
let(:notification_dropdown_items) { '["global","watch","participating","mention","disabled"]' }
context "returns default user notification settings" do
let(:expected) do
{
emails_disabled: "false",
notification_dropdown_items: notification_dropdown_items,
notification_help_page_path: notification_help_path,
notification_level: "global"
}
end
subject { helper.notification_data_attributes(project) }
it { is_expected.to eq(expected) }
end
context "returns configured users notification settings" do
before do
allow(project).to receive(:emails_disabled?).and_return(true)
setting = user.notification_settings_for(project)
setting.level = :watch
setting.save!
end
let(:expected) do
{
emails_disabled: "true",
notification_dropdown_items: notification_dropdown_items,
notification_help_page_path: notification_help_path,
notification_level: "watch"
}
end
subject { helper.notification_data_attributes(project) }
it { is_expected.to eq(expected) }
end
end
describe '#home_panel_data_attributes' do
using RSpec::Parameterized::TableSyntax
before do
allow(helper).to receive(:groups_projects_more_actions_dropdown_data).and_return(nil)
allow(helper).to receive(:fork_button_data_attributes).and_return(nil)
allow(helper).to receive(:notification_data_attributes).and_return(nil)
allow(helper).to receive(:star_count_data_attributes).and_return({})
end
where(:can_read_project, :is_empty_repo) do
true | true
false | false
end
with_them do
context "returns default user project details" do
before do
allow(helper).to receive(:can?).with(user, :read_project, project).and_return(can_read_project)
allow(project).to receive(:empty_repo?).and_return(is_empty_repo)
end
let(:expected) do
{
can_read_project: can_read_project.to_s,
is_project_empty: is_empty_repo.to_s,
project_id: project.id
}
end
subject { helper.home_panel_data_attributes }
it { is_expected.to eq(expected) }
end
end
end
shared_examples 'configure import method modal' do
context 'as a user' do
it 'returns a link to contact an administrator' do

View File

@ -408,7 +408,7 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
describe '#full_path' do
it 'returns group full path for project entity' do
it 'returns group full path for group entity' do
group_entity = build(:bulk_import_entity, :group_entity, group: build(:group))
expect(group_entity.full_path).to eq(group_entity.group.full_path)
@ -427,6 +427,26 @@ RSpec.describe BulkImports::Entity, type: :model, feature_category: :importers d
end
end
describe '#full_path_with_fallback' do
it 'returns group full path for group entity' do
group_entity = build(:bulk_import_entity, :group_entity, group: build(:group))
expect(group_entity.full_path_with_fallback).to eq(group_entity.group.full_path)
end
it 'returns project full path for project entity' do
project_entity = build(:bulk_import_entity, :project_entity, project: build(:project))
expect(project_entity.full_path_with_fallback).to eq(project_entity.project.full_path)
end
it 'returns fallback full path when not associated with group or project' do
entity = build(:bulk_import_entity, group: nil, project: nil)
expect(entity.full_path_with_fallback).to eq("#{entity.destination_namespace}/#{entity.destination_slug}")
end
end
describe '#default_visibility_level' do
context 'when entity is a group' do
it 'returns default group visibility' do

View File

@ -216,16 +216,11 @@ RSpec.configure do |config|
# This includes the first try, i.e. tests will be run 2 times before failing.
config.default_retry_count = ENV.fetch('RETRIES', 1).to_i + 1
# Do not retry controller tests because rspec-retry cannot properly
# reset the controller which may contain data from last attempt. See
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73360
config.prepend_before(:each, type: :controller) do |example|
example.metadata[:retry] = 1
end
# Gradually stop using rspec-retry
# See https://gitlab.com/gitlab-org/gitlab/-/issues/438388
%i[
bin channels commands components config contracts controller db
dependencies dot_gitlab_ci experiments finders
graphql haml_lint helpers initializers keeps lib mailers metrics_server
migrations models policies presenters rack_servers requests
routing rubocop scripts serializers services sidekiq sidekiq_cluster

View File

@ -29,8 +29,8 @@ module CycleAnalyticsHelpers
def select_event_label(sel)
page.within(sel) do
find('.dropdown-toggle').click
page.find(".dropdown-menu").all(".dropdown-item")[1].click
find('[data-testid="base-dropdown-toggle"]').click
page.find('[data-testid="base-dropdown-menu"]').all(".gl-new-dropdown-item")[1].click
end
end

View File

@ -53,7 +53,7 @@ RSpec.shared_examples 'variable list pagination' do |variable_type|
end
page.within('[data-testid="ci-variable-table"]') do
find('.b-table-sort-icon-left').click
find('[aria-sort="ascending"]').click
end
wait_for_requests

View File

@ -37,44 +37,17 @@ RSpec.describe 'projects/_home_panel' do
end
end
context 'notifications' do
context 'home panel' do
let(:project) { create(:project) }
before do
assign(:project, project)
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:can?).with(user, :read_project, project).and_return(false)
allow(project).to receive(:license_anchor_data).and_return(false)
end
context 'when user is signed in' do
let(:user) { create(:user) }
it 'renders Vue app root' do
render
before do
notification_settings = user.notification_settings_for(project)
assign(:notification_setting, notification_settings)
end
it 'renders Vue app root' do
render
expect(rendered).to have_selector('.js-vue-notification-dropdown')
end
end
context 'when user is signed out' do
let(:user) { nil }
before do
assign(:notification_setting, nil)
end
it 'does not render Vue app root' do
render
expect(rendered).not_to have_selector('.js-vue-notification-dropdown')
end
expect(rendered).to have_selector('#js-home-panel')
end
end

View File

@ -87,7 +87,7 @@ RSpec.describe 'shared/projects/_list' do
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|Explore public groups to find projects to contribute to.'))
expect(rendered).to have_content(s_('UserProfile|Explore public groups to find projects to contribute to'))
end
end
@ -95,7 +95,7 @@ RSpec.describe 'shared/projects/_list' do
it 'renders a no-content message' do
render
expect(rendered).to have_content(s_('UserProfile|There are no projects available to be displayed here.'))
expect(rendered).to have_content(s_('UserProfile|There are no projects available to be displayed here'))
end
end
end

View File

@ -1326,10 +1326,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.84.0.tgz#4c251a528c825875b3062be236ae2a06569c9f45"
integrity sha512-v6Sh3VRVTelWY+yPJ/kWm1A4y0Ox1xgecXljVd7BpB0S9OboK2J5AXbwzqit6s4TSab/B8G3Vf5g4fHsVQCXqg==
"@gitlab/ui@^74.9.1":
version "74.9.1"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-74.9.1.tgz#0500fcc3b50d373e391eaf959f44166050c35c5e"
integrity sha512-itEFQUgqfl3l/5lBOtBTpIWbu3DyEH9YsBDbgtouxOlWammEi/DmW+dQ45DzeHrJdkbfzGW2fwLd4mn1i89Mew==
"@gitlab/ui@^74.9.3":
version "74.9.3"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-74.9.3.tgz#c78e7962f9abd35134680c8e5f68e40565a27a9b"
integrity sha512-HoIPtsMaQ/Qj2DEX6AqJSWD+CPFAOxw1b1b/jGLQKJHwvR02ff+CNgE4Gv3luCfOVWlEwIiZfLwIorACZG6flg==
dependencies:
"@floating-ui/dom" "1.4.3"
bootstrap-vue "2.23.1"