Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-08-02 18:10:14 +00:00
parent 948b3c5ace
commit 48902b7e07
132 changed files with 1124 additions and 540 deletions

View File

@ -265,7 +265,7 @@ export default {
type="file"
accept="image/*"
name="avatar_file"
class="gl-display-none"
class="gl-hidden"
@change="selectFile"
/>
</div>

View File

@ -11,9 +11,9 @@ export default () => {
const denyAllRequestsWarning = document.querySelector('.js-deny-all-requests-warning');
if (denyAll) {
denyAllRequestsWarning.classList.remove('gl-display-none');
denyAllRequestsWarning.classList.remove('gl-hidden');
} else {
denyAllRequestsWarning.classList.add('gl-display-none');
denyAllRequestsWarning.classList.add('gl-hidden');
}
allowLocalRequests.forEach((allowLocalRequest) => {

View File

@ -80,7 +80,7 @@ export default {
:items="items"
:fields="$options.fields"
show-empty
thead-class="gl-display-none"
thead-class="gl-hidden"
/>
<div
v-if="isTooLarge"

View File

@ -10,7 +10,7 @@ export default class LegacyTemplateSelector {
this.$dropdownContainer = wrapper;
this.$filenameInput = $input || $('#file_name');
this.dropdownIcon = dropdown[0].querySelector('.dropdown-menu-toggle-icon');
this.loadingIcon = loadingIconForLegacyJS({ classes: ['gl-display-none'] });
this.loadingIcon = loadingIconForLegacyJS({ classes: ['gl-hidden'] });
this.dropdownIcon.parentNode.insertBefore(this.loadingIcon, this.dropdownIcon.nextSibling);
this.initDropdown(dropdown, data);
@ -99,12 +99,12 @@ export default class LegacyTemplateSelector {
}
startLoadingSpinner() {
this.loadingIcon.classList.remove('gl-display-none');
this.dropdownIcon.classList.add('gl-display-none');
this.loadingIcon.classList.remove('gl-hidden');
this.dropdownIcon.classList.add('gl-hidden');
}
stopLoadingSpinner() {
this.loadingIcon.classList.add('gl-display-none');
this.dropdownIcon.classList.remove('gl-display-none');
this.loadingIcon.classList.add('gl-hidden');
this.dropdownIcon.classList.remove('gl-hidden');
}
}

View File

@ -42,8 +42,8 @@ export default () => {
});
commitButton.on('click', () => {
commitButton.addClass('gl-display-none');
commitButtonLoading.removeClass('gl-display-none');
commitButton.addClass('gl-hidden');
commitButtonLoading.removeClass('gl-hidden');
window.onbeforeunload = null;
});

View File

@ -373,7 +373,7 @@ export default {
<div
class="board-title-text"
:class="{
'gl-display-none': list.collapsed && isSwimlanesHeader,
'gl-hidden': list.collapsed && isSwimlanesHeader,
'gl-flex-grow-0 gl-my-3 gl-mx-0': list.collapsed,
'gl-flex-grow-1': !list.collapsed,
'gl-rotate-90': list.collapsed,

View File

@ -40,6 +40,6 @@ export default {
<file-icon class="file-row-icon" :file-name="fileName" />
<span>{{ fileName }}</span>
</span>
<gl-icon class="gl-display-none gl-relative gl-text-gray-500" name="external-link" />
<gl-icon class="gl-hidden gl-relative gl-text-gray-500" name="external-link" />
</gl-link>
</template>

View File

@ -15,11 +15,17 @@ import { s__, sprintf } from '~/locale';
import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
import { queryToObject } from '~/lib/utils/url_utility';
import { reportToSentry } from '~/ci/utils';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql';
import playPipelineScheduleMutation from '../graphql/mutations/play_pipeline_schedule.mutation.graphql';
import takeOwnershipMutation from '../graphql/mutations/take_ownership.mutation.graphql';
import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql';
import { ALL_SCOPE, SCHEDULES_PER_PAGE, DEFAULT_SORT_VALUE } from '../constants';
import {
ALL_SCOPE,
SCHEDULES_PER_PAGE,
DEFAULT_SORT_VALUE,
TABLE_SORT_STORAGE_KEY,
} from '../constants';
import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
import TakeOwnershipModal from './take_ownership_modal.vue';
import DeletePipelineScheduleModal from './delete_pipeline_schedule_modal.vue';
@ -54,6 +60,7 @@ export default {
),
planLimitReachedBtnText: s__('PipelineSchedules|Explore plan limits'),
},
sortStorageKey: TABLE_SORT_STORAGE_KEY,
docsLink: helpPagePath('administration/instance_limits', {
anchor: 'number-of-pipeline-schedules',
}),
@ -68,6 +75,7 @@ export default {
GlTab,
GlSprintf,
GlLink,
LocalStorageSync,
PipelineSchedulesTable,
TakeOwnershipModal,
PipelineScheduleEmptyState,
@ -207,6 +215,16 @@ export default {
shouldDisableNewScheduleBtn() {
return (this.hasReachedPlanLimit || this.hasNoAccess) && !this.hasUnlimitedSchedules;
},
sortingState: {
get() {
return { sortValue: this.sortValue, sortBy: this.sortBy, sortDesc: this.sortDesc };
},
set(values) {
this.sortValue = values.sortValue;
this.sortBy = values.sortBy;
this.sortDesc = values.sortDesc;
},
},
},
watch: {
// this watcher ensures that the count on the all tab
@ -380,6 +398,8 @@ export default {
</gl-button>
</gl-alert>
<local-storage-sync v-model="sortingState" :storage-key="$options.sortStorageKey" />
<pipeline-schedule-empty-state v-if="showEmptyState" />
<gl-tabs

View File

@ -7,3 +7,5 @@ export const DEFAULT_SORT_VALUE = 'ID_DESC';
export const TH_DESCRIPTION_TEST_ID = { 'data-testid': 'pipeline-schedules-description-sort' };
export const TH_TARGET_TEST_ID = { 'data-testid': 'pipeline-schedules-target-sort' };
export const TH_NEXT_TEST_ID = { 'data-testid': 'pipeline-schedules-next-sort' };
export const TABLE_SORT_STORAGE_KEY = 'pipeline_schedule_table_sort';

View File

@ -45,7 +45,7 @@ export default {
},
computed: {
bodyClasses() {
return this.isExpanded ? '' : 'gl-display-none';
return this.isExpanded ? '' : 'gl-hidden';
},
failedJobsCountText() {
return sprintf(this.$options.i18n.failedJobsLabel, { count: this.currentFailedJobsCount });

View File

@ -233,7 +233,7 @@ export default {
:count-scope="$options.INSTANCE_TYPE"
:count-variables="countVariables"
class="gl-w-full"
content-class="gl-display-none"
content-class="gl-hidden"
nav-class="gl-border-none!"
/>
</div>

View File

@ -248,7 +248,7 @@ export default {
:count-variables="countVariables"
:runner-types="$options.TABS_RUNNER_TYPES"
class="gl-w-full"
content-class="gl-display-none"
content-class="gl-hidden"
nav-class="gl-border-none!"
/>
</div>

View File

@ -22,7 +22,7 @@ export default class ImageFile {
initViewModes() {
const viewMode = viewModes[0];
$('.view-modes', this.file).removeClass('gl-display-none');
$('.view-modes', this.file).removeClass('gl-hidden');
$('.view-modes-menu', this.file).on('click', 'li', (event) => {
if (!$(event.currentTarget).hasClass('active')) {
return this.activateViewMode(event.currentTarget.className);
@ -37,8 +37,8 @@ export default class ImageFile {
.filter(`.${viewMode}`)
.addClass('active');
$(`.view:visible:not(.${viewMode})`, this.file).addClass('gl-display-none');
$(`.view.${viewMode}`, this.file).removeClass('gl-display-none');
$(`.view:visible:not(.${viewMode})`, this.file).addClass('gl-hidden');
$(`.view.${viewMode}`, this.file).removeClass('gl-hidden');
return this.initView(viewMode);
}
@ -111,7 +111,7 @@ export default class ImageFile {
return this.requestImageInfo($('img', wrap), (width, height) => {
$('.image-info .meta-width', wrap).text(`${width}px`);
$('.image-info .meta-height', wrap).text(`${height}px`);
return $('.image-info', wrap).removeClass('gl-display-none');
return $('.image-info', wrap).removeClass('gl-hidden');
});
});
},

View File

@ -88,7 +88,7 @@ export default {
},
showWarning() {
if (this.warningText) {
this.warningText.classList.remove('gl-display-none');
this.warningText.classList.remove('gl-hidden');
}
},
},

View File

@ -237,7 +237,7 @@ export default {
type="file"
name="content_editor_image"
:accept="$options.acceptedMimes[mediaType]"
class="gl-display-none"
class="gl-hidden"
@change="onFileSelect"
/>
<gl-link

View File

@ -56,7 +56,7 @@ export default {
type="file"
multiple
name="content_editor_image"
class="gl-display-none"
class="gl-hidden"
:aria-label="$options.i18n.inputLabel"
data-testid="file-upload-field"
@change="onFileSelect"

View File

@ -1360,8 +1360,8 @@ export default class Notes {
const $svgChevronUpElement = $element.find('svg.js-chevron-up');
const $svgChevronDownElement = $element.find('svg.js-chevron-down');
$svgChevronUpElement.toggleClass('gl-display-none');
$svgChevronDownElement.toggleClass('gl-display-none');
$svgChevronUpElement.toggleClass('gl-hidden');
$svgChevronDownElement.toggleClass('gl-hidden');
$closestSystemCommitList.toggleClass('hide-shade');
}

View File

@ -52,7 +52,7 @@ export default {
type="file"
name="design_file"
:accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
class="gl-display-none"
class="gl-hidden"
multiple
@change="onFileUploadChange"
/>

View File

@ -51,7 +51,7 @@ export default {
<b>{{ folderName }}</b>
</h4>
<gl-tabs v-if="!isLoading" scope="environments" content-class="gl-display-none">
<gl-tabs v-if="!isLoading" scope="environments" content-class="gl-hidden">
<gl-tab
v-for="(tab, i) in tabs"
:key="`${tab.name}-${i}`"

View File

@ -489,7 +489,7 @@ export default {
<template>
<div id="ide" class="blob-viewer-container blob-editor-container">
<gl-tabs v-if="showTabs" content-class="gl-display-none">
<gl-tabs v-if="showTabs" content-class="gl-hidden">
<gl-tab
:title="__('Edit')"
data-testid="edit-tab"

View File

@ -72,9 +72,8 @@ export default {
fields.push({
key: 'updated_at',
label: this.showUpdatedAt ? __('Last updated') : '',
thClass: 'gl-display-none d-sm-table-cell gl-text-right',
tdClass:
'gl-border-bottom-0! gl-text-right gl-display-none d-sm-table-cell !gl-align-middle',
thClass: 'gl-hidden d-sm-table-cell gl-text-right',
tdClass: 'gl-border-bottom-0! gl-text-right gl-hidden d-sm-table-cell !gl-align-middle',
});
}

View File

@ -0,0 +1,123 @@
<script>
import { GlAvatar, GlPopover, GlSkeletonLoader, GlSprintf } from '@gitlab/ui';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_NOTE } from '~/graphql_shared/constants';
import SafeHtml from '~/vue_shared/directives/safe_html';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import noteQuery from '../queries/note.query.graphql';
import { renderGFM } from '../../../behaviors/markdown/render_gfm';
export default {
safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
components: {
GlAvatar,
GlPopover,
GlSkeletonLoader,
GlSprintf,
},
directives: {
SafeHtml,
},
mixins: [timeagoMixin],
props: {
target: {
type: HTMLAnchorElement,
required: true,
},
},
apollo: {
note: {
skip() {
return !this.noteId;
},
query: noteQuery,
variables() {
return {
id: convertToGraphQLId(TYPENAME_NOTE, this.noteId),
};
},
result(result) {
if (result?.errors?.length > 0) {
this.fallback();
return null;
}
if (!result?.data?.note) {
this.fallback();
return null;
}
return result.data.note;
},
error() {
this.fallback();
},
},
},
data() {
return {
note: null,
show: true,
};
},
computed: {
loading() {
return this.$apollo.queries.note?.loading;
},
urlHash() {
return this.target.href.split('#')[1] || '';
},
noteId() {
const [, noteId] = this.urlHash.match(/note_([0-9]+)/) || [];
return noteId || '';
},
author() {
return this.note?.author;
},
noteCreatedAt() {
return this.timeFormatted(this.note?.createdAt);
},
noteText() {
// for empty line (if it's an image or other non-text content)
if (this.note?.bodyFirstLineHtml === '<p></p>') {
return '';
}
return this.note?.bodyFirstLineHtml;
},
},
methods: {
renderGFM() {
renderGFM(this.$refs.gfm);
},
fallback() {
this.show = false;
},
},
cssClasses: ['gl-max-w-48', 'gl-overflow-hidden'],
};
</script>
<template>
<gl-popover :target="target" boundary="viewport" :css-classes="$options.cssClasses" :show="show">
<gl-skeleton-loader v-if="loading" :lines="2" :height="24" equal-width-lines />
<div v-if="author" class="gl-text-secondary gl-flex gl-gap-2">
<gl-avatar :src="author.avatarUrl" :size="16" />
<div>
<gl-sprintf :message="__('%{author} commented %{time}')">
<template #author>
<span class="gl-text-sm gl-break-all">{{ author.name }}</span>
</template>
<template #time>
<span class="gl-text-sm">{{ noteCreatedAt }}</span>
</template>
</gl-sprintf>
</div>
</div>
<div
v-if="noteText"
ref="gfmContent"
v-safe-html:[$options.safeHtmlConfig]="noteText"
class="md gl-mt-2"
></div>
</gl-popover>
</template>

View File

@ -4,6 +4,7 @@ import createDefaultClient from '~/lib/graphql';
import IssuePopover from './components/issue_popover.vue';
import MRPopover from './components/mr_popover.vue';
import MilestonePopover from './components/milestone_popover.vue';
import CommentPopover from './components/comment_popover.vue';
export const componentsByReferenceTypeMap = {
issue: IssuePopover,
@ -24,6 +25,24 @@ const handleIssuablePopoverMouseOut = ({ target }) => {
const popoverMountedAttr = 'data-popover-mounted';
function isCommentPopover(target) {
const targetUrl = new URL(target.href);
const noteId = targetUrl.hash;
return window?.gon?.features?.commentTooltips && noteId && noteId.startsWith('#note_');
}
export function handleCommentPopoverMount({ target, apolloProvider }) {
const PopoverComponent = Vue.extend(CommentPopover);
new PopoverComponent({
propsData: {
target,
},
apolloProvider,
}).$mount();
}
/**
* Adds a Popover component for issuables and work items to the body,
* hands over as much data as the target element has in data attributes.
@ -45,17 +64,22 @@ export const handleIssuablePopoverMount = ({
target.addEventListener('mouseleave', handleIssuablePopoverMouseOut);
renderFn = setTimeout(() => {
const PopoverComponent = Vue.extend(componentsByReferenceType[referenceType]);
new PopoverComponent({
propsData: {
target,
namespacePath,
iid,
milestoneId: milestone,
cachedTitle: title || innerText,
},
apolloProvider,
}).$mount();
if (isCommentPopover(target)) {
handleCommentPopoverMount({ target, apolloProvider });
} else {
const PopoverComponent = Vue.extend(componentsByReferenceType[referenceType]);
new PopoverComponent({
propsData: {
target,
namespacePath,
iid,
milestoneId: milestone,
cachedTitle: title || innerText,
},
apolloProvider,
}).$mount();
}
target.setAttribute(popoverMountedAttr, true);
}, 200); // 200ms delay so not every mouseover triggers Popover + API Call
@ -72,9 +96,10 @@ export default (elements, issuablePopoverMount = handleIssuablePopoverMount) =>
elements.forEach((el) => {
const { projectPath, groupPath, iid, referenceType, milestone, project } = el.dataset;
let { namespacePath } = el.dataset;
const title = el.dataset.mrTitle || el.title;
const { innerText } = el;
const namespacePath = groupPath || projectPath;
namespacePath = namespacePath || groupPath || projectPath;
const isIssuable = Boolean(namespacePath && title && iid);
const isMilestone = Boolean(milestone && project);

View File

@ -0,0 +1,13 @@
#import "~/graphql_shared/fragments/author.fragment.graphql"
query note($id: NoteID!) {
note(id: $id) {
id
author {
...Author
}
bodyFirstLineHtml
createdAt
internal
}
}

View File

@ -41,7 +41,7 @@ export default class LabelsSelect {
const $form = $dropdown.closest('form, .js-issuable-update');
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span');
const $value = $block.find('.value');
const $loading = $block.find('.block-loading').addClass('gl-display-none');
const $loading = $block.find('.block-loading').addClass('gl-hidden');
const fieldName = $dropdown.data('fieldName');
let initialSelected = $selectbox
.find(`input[name="${$dropdown.data('fieldName')}"]`)
@ -78,13 +78,13 @@ export default class LabelsSelect {
if (!selected.length) {
data[abilityName].label_ids = [''];
}
$loading.removeClass('gl-display-none');
$loading.removeClass('gl-hidden');
$dropdown.trigger('loading.gl.dropdown');
axios
.put(issueUpdateURL, data)
.then(({ data }) => {
let template;
$loading.addClass('gl-display-none');
$loading.addClass('gl-hidden');
$dropdown.trigger('loaded.gl.dropdown');
$selectbox.hide();
data.issueUpdateURL = issueUpdateURL;

View File

@ -227,3 +227,8 @@ export const I18N_USER_BOT = __('Bot');
export const I188N_USER_2FA = __('2FA');
export const I18N_ROLE_SAVE_SUCCESS = s__('Members|Role was successfully updated.');
export const I18N_ROLE_SAVE_ERROR = s__('MemberRole|Could not update role.');
export const CONTEXT_TYPE = Object.freeze({
PROJECT: 'PROJECT',
GROUP: 'GROUP',
});

View File

@ -9,7 +9,12 @@ import { TABS } from 'ee_else_ce/members/tabs_metadata';
import MembersTabs from './components/members_tabs.vue';
import membersStore from './store';
export const initMembersApp = (el, options) => {
/**
* @param {HTMLElement} el
* @param {string} context as defined in CONTEXT_TYPE in ./constants.js
* @param {Object} options
*/
export const initMembersApp = (el, context, options) => {
if (!el) {
return () => {};
}
@ -27,6 +32,7 @@ export const initMembersApp = (el, options) => {
exportCsvPath,
groupName,
groupPath,
projectPath,
manageMemberRolesPath,
canApproveAccessRequests,
namespaceUserLimit,
@ -69,10 +75,14 @@ export const initMembersApp = (el, options) => {
canApproveAccessRequests,
namespaceUserLimit,
availableRoles,
context,
group: {
name: groupName,
path: groupPath,
},
project: {
path: projectPath,
},
},
render: (createElement) => createElement('members-tabs'),
});

View File

@ -77,7 +77,7 @@ export default class SSHMirror {
// Disable button while we make request
this.$btnDetectHostKeys.disable();
$btnLoadSpinner.removeClass('gl-display-none');
$btnLoadSpinner.removeClass('gl-hidden');
// Make backOff polling to get data
backOff((next, stop) => {
@ -102,7 +102,7 @@ export default class SSHMirror {
.catch(stop);
})
.then((res) => {
$btnLoadSpinner.addClass('gl-display-none');
$btnLoadSpinner.addClass('gl-hidden');
// Once data is received, we show verification info along with Host keys and fingerprints
this.$hostKeysInformation
.find('.js-fingerprint-verification')

View File

@ -56,7 +56,7 @@ export default {
methods: {
tagBadgeClass(index) {
return {
'gl-display-none': true,
'gl-hidden': true,
'gl-display-flex': this.tagCount === 1,
'md:!gl-flex': this.tagCount > 1,
'gl-mr-2': index !== this.tagsToRender.length - 1,

View File

@ -51,13 +51,13 @@ export default class PayloadPreviewer {
hidePayload() {
this.isVisible = false;
this.getContainer().classList.add('gl-display-none');
this.getContainer().classList.add('gl-hidden');
this.text.textContent = __('Preview payload');
}
showPayload() {
this.isVisible = true;
this.getContainer().classList.remove('gl-display-none');
this.getContainer().classList.remove('gl-hidden');
this.text.textContent = __('Hide payload');
}

View File

@ -3,7 +3,7 @@ import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
import initInviteGroupsModal from '~/invite_members/init_invite_groups_modal';
import { s__ } from '~/locale';
import { initMembersApp } from '~/members';
import { GROUPS_APP_OPTIONS, MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import { CONTEXT_TYPE, GROUPS_APP_OPTIONS, MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import { groupLinkRequestFormatter } from '~/members/utils';
const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
@ -59,7 +59,11 @@ const APP_OPTIONS = {
...GROUPS_APP_OPTIONS,
};
initMembersApp(document.querySelector('.js-group-members-list-app'), APP_OPTIONS);
initMembersApp(
document.querySelector('.js-group-members-list-app'),
CONTEXT_TYPE.GROUP,
APP_OPTIONS,
);
initInviteGroupsModal();
initInviteGroupTrigger();

View File

@ -1,4 +1,8 @@
import { PROJECTS_APP_OPTIONS, MEMBERS_TAB_TYPES } from 'ee_else_ce/members/constants';
import {
PROJECTS_APP_OPTIONS,
MEMBERS_TAB_TYPES,
CONTEXT_TYPE,
} from 'ee_else_ce/members/constants';
import initImportProjectMembersTrigger from '~/invite_members/init_import_project_members_trigger';
import initImportProjectMembersModal from '~/invite_members/init_import_project_members_modal';
import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger';
@ -14,7 +18,7 @@ initInviteGroupTrigger();
initImportProjectMembersTrigger();
const SHARED_FIELDS = ['account', 'maxRole', 'expiration', 'actions'];
initMembersApp(document.querySelector('.js-project-members-list-app'), {
initMembersApp(document.querySelector('.js-project-members-list-app'), CONTEXT_TYPE.PROJECT, {
[MEMBERS_TAB_TYPES.user]: {
tableFields: SHARED_FIELDS.concat(['source', 'activity']),
tableSortableFields: [

View File

@ -11,7 +11,7 @@ export const initDetailsButton = () => {
if (contentEl) {
contentEl.classList.remove('hide');
btn.classList.add('gl-display-none');
btn.classList.add('gl-hidden');
}
});
};

View File

@ -81,11 +81,11 @@ const validateGroupNamespaceDropdown = (e) => {
e.preventDefault();
dropdownButton().classList.add(invalidDropdownClass);
namespaceButton().classList.add(invalidDropdownClass);
namespaceError().classList.remove('gl-display-none');
namespaceError().classList.remove('gl-hidden');
} else {
dropdownButton().classList.remove(invalidDropdownClass);
namespaceButton().classList.remove(invalidDropdownClass);
namespaceError().classList.add('gl-display-none');
namespaceError().classList.add('gl-hidden');
}
};
@ -96,11 +96,11 @@ const checkProjectName = (projectNameInput) => {
if (!projectNameError) return;
if (msg) {
projectNameError.innerText = msg;
projectNameError.classList.remove('gl-display-none');
projectNameDescription.classList.add('gl-display-none');
projectNameError.classList.remove('gl-hidden');
projectNameDescription.classList.add('gl-hidden');
} else {
projectNameError.classList.add('gl-display-none');
projectNameDescription.classList.remove('gl-display-none');
projectNameError.classList.add('gl-hidden');
projectNameDescription.classList.remove('gl-hidden');
}
};
@ -123,7 +123,7 @@ const setProjectNamePathHandlers = ($projectNameInput, $projectPathInput) => {
hasUserDefinedProjectPath = $projectPathInput.value.trim().length > 0;
specialRepo.classList.toggle(
'gl-display-none',
'gl-hidden',
$projectPathInput.value !== $projectPathInput.dataset.username,
);
};

View File

@ -63,7 +63,7 @@ export default function initReadMore(triggerSelector = '.js-read-more-trigger')
return;
}
triggerEl.classList.remove('gl-display-none');
triggerEl.classList.remove('gl-hidden');
}
triggerEl.addEventListener(

View File

@ -2,7 +2,7 @@
export const EXCLUDED_NODES = ['OPTION'];
// Used to hide the sections that do not match * the search term
export const HIDE_CLASS = 'gl-display-none';
export const HIDE_CLASS = 'gl-hidden';
// used to highlight the text that matches the * search term
export const HIGHLIGHT_CLASS = 'gl-bg-orange-100';

View File

@ -71,11 +71,11 @@ function initGlobalProtectionOptions() {
globalProtectionProtectedOption.forEach((option) => {
const isProtected = parseBoolean(option.value);
option.addEventListener('change', () => {
protectionSettingsSection.classList.toggle('gl-display-none', !isProtected);
protectionSettingsSection.classList.toggle('gl-hidden', !isProtected);
});
if (option.checked) {
protectionSettingsSection.classList.toggle('gl-display-none', !isProtected);
protectionSettingsSection.classList.toggle('gl-hidden', !isProtected);
}
});
}

View File

@ -29,8 +29,8 @@ const REVIEW_STATE_ICONS = {
title: s__('MergeRequest|Awaiting review'),
},
REVIEW_STARTED: {
name: 'status_running',
class: 'gl-text-blue-500',
name: 'comment-dots',
class: 'gl-text-gray-500',
title: s__('MergeRequest|Reviewer started review'),
},
};

View File

@ -42,11 +42,11 @@ export default class SingleFileDiff {
this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide();
this.content = null;
this.collapsedContent.after(this.loadingContent);
this.$chevronRightIcon.removeClass('gl-display-none');
this.$chevronRightIcon.removeClass('gl-hidden');
} else {
this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide();
this.content.after(this.collapsedContent);
this.$chevronDownIcon.removeClass('gl-display-none');
this.$chevronDownIcon.removeClass('gl-hidden');
}
$('.js-file-title', this.file).on('click', (e) => {
@ -67,17 +67,17 @@ export default class SingleFileDiff {
this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) {
this.content.hide();
this.$chevronRightIcon.removeClass('gl-display-none');
this.$chevronDownIcon.addClass('gl-display-none');
this.$chevronRightIcon.removeClass('gl-hidden');
this.$chevronDownIcon.addClass('gl-hidden');
this.collapsedContent.show();
} else if (this.content) {
this.collapsedContent.hide();
this.content.show();
this.$chevronDownIcon.removeClass('gl-display-none');
this.$chevronRightIcon.addClass('gl-display-none');
this.$chevronDownIcon.removeClass('gl-hidden');
this.$chevronRightIcon.addClass('gl-hidden');
} else {
this.$chevronDownIcon.removeClass('gl-display-none');
this.$chevronRightIcon.addClass('gl-display-none');
this.$chevronDownIcon.removeClass('gl-hidden');
this.$chevronRightIcon.addClass('gl-hidden');
return this.getContentHTML(cb); // eslint-disable-line consistent-return
}
}

View File

@ -284,7 +284,7 @@ export default {
:key="shortcutLink.href"
:href="shortcutLink.href"
:class="shortcutLink.css_class"
class="gl-display-none"
class="gl-hidden"
>
{{ shortcutLink.title }}
</a>

View File

@ -52,7 +52,7 @@ export default {
:items="items"
:fields="$options.fields"
:tbody-tr-attr="{ 'data-testid': 'token-access-table-row' }"
thead-class="gl-display-none"
thead-class="gl-hidden"
class="gl-mb-0"
fixed
>

View File

@ -174,7 +174,7 @@ export default {
await updateRepositorySize(this.projectPath);
this.loadingRecalculateSize = false;
alertEl?.classList.remove('gl-display-none');
alertEl?.classList.remove('gl-hidden');
},
},
usageQuotasHelpPaths,

View File

@ -69,7 +69,7 @@ export default {
<div aria-hidden="true">
<gl-link
:id="anchorLinkId"
class="gl-text-decoration-none gl-display-none"
class="gl-text-decoration-none gl-hidden"
:href="anchorLink"
/>
</div>

View File

@ -137,7 +137,7 @@ export default {
return this.workItem?.author;
},
workItemDevelopment() {
return this.isWidgetPresent(WIDGET_TYPE_DEVELOPMENT) && this.glFeatures.workItemsAlpha;
return this.isWidgetPresent(WIDGET_TYPE_DEVELOPMENT) && this.glFeatures.workItemsBeta;
},
hasParent() {
return this.workItemHierarchy?.hasParent;

View File

@ -1,5 +1,6 @@
<script>
import { GlLoadingIcon, GlIcon, GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { s__, __ } from '~/locale';
@ -19,6 +20,7 @@ export default {
GlTooltip: GlTooltipDirective,
GlModal: GlModalDirective,
},
mixins: [glFeatureFlagMixin()],
props: {
canUpdate: {
type: Boolean,
@ -79,6 +81,9 @@ export default {
linkedMergeRequests() {
return this.workItemDevelopment?.closingMergeRequests?.nodes || [];
},
shouldShowDevWidget() {
return this.glFeatures.workItemsAlpha ? true : !this.isEmptyRelatedWorkItems;
},
isEmptyRelatedWorkItems() {
return !this.error && this.linkedMergeRequests.length === 0;
},
@ -121,7 +126,7 @@ export default {
};
</script>
<template>
<div>
<div v-if="shouldShowDevWidget">
<div class="gl-flex gl-items-center gl-gap-3 gl-justify-between">
<h3
class="gl-mb-0! gl-heading-5 gl-flex gl-items-center gl-gap-2"

View File

@ -1,20 +1,23 @@
<script>
import { GlLink, GlIcon, GlPopover } from '@gitlab/ui';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { s__ } from '~/locale';
import WorkItemSidebarDropdownWidget from '~/work_items/components/shared/work_item_sidebar_dropdown_widget.vue';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import { isValidURL } from '~/lib/utils/url_utility';
import { updateParent } from '../graphql/cache_utils';
import groupWorkItemsQuery from '../graphql/group_work_items.query.graphql';
import projectWorkItemsQuery from '../graphql/project_work_items.query.graphql';
import workItemsByReferencesQuery from '../graphql/work_items_by_references.query.graphql';
import {
I18N_WORK_ITEM_ERROR_UPDATING,
sprintfWorkItem,
SUPPORTED_PARENT_TYPE_MAP,
WORK_ITEM_TYPE_VALUE_ISSUE,
} from '../constants';
import { isReference } from '../utils';
export default {
name: 'WorkItemParent',
@ -69,10 +72,9 @@ export default {
},
data() {
return {
search: '',
searchTerm: '',
updateInProgress: false,
searchStarted: false,
availableWorkItems: [],
localSelectedItem: this.parent?.id,
oldParent: this.parent,
};
@ -82,7 +84,13 @@ export default {
return this.workItemType === WORK_ITEM_TYPE_VALUE_ISSUE;
},
isLoading() {
return this.$apollo.queries.availableWorkItems.loading;
return (
this.$apollo.queries.workspaceWorkItems.loading ||
this.$apollo.queries.workItemsByReference.loading
);
},
availableWorkItems() {
return this.isSearchingByReference ? this.workItemsByReference : this.workspaceWorkItems;
},
listboxText() {
return (
@ -92,7 +100,7 @@ export default {
);
},
workItems() {
return this.availableWorkItems.map(({ id, title }) => ({ text: title, value: id }));
return this.availableWorkItems?.map(({ id, title }) => ({ text: title, value: id })) || [];
},
parentType() {
return SUPPORTED_PARENT_TYPE_MAP[this.workItemType];
@ -103,6 +111,9 @@ export default {
showCustomNoneValue() {
return this.hasParent && this.parent === null;
},
isSearchingByReference() {
return isReference(this.searchTerm) || isValidURL(this.searchTerm);
},
},
watch: {
parent: {
@ -112,7 +123,7 @@ export default {
},
},
apollo: {
availableWorkItems: {
workspaceWorkItems: {
query() {
// TODO: Remove the this.isIssue check once issues are migrated to work items
return this.isGroup || this.isIssue ? groupWorkItemsQuery : projectWorkItemsQuery;
@ -121,9 +132,9 @@ export default {
// TODO: Remove the this.isIssue check once issues are migrated to work items
return {
fullPath: this.isIssue ? this.groupPath : this.fullPath,
searchTerm: this.search,
searchTerm: this.searchTerm,
types: this.parentType,
in: this.search ? 'TITLE' : undefined,
in: this.searchTerm ? 'TITLE' : undefined,
iid: null,
isNumber: false,
includeAncestors: true,
@ -139,10 +150,28 @@ export default {
this.$emit('error', this.$options.i18n.workItemsFetchError);
},
},
workItemsByReference: {
query: workItemsByReferencesQuery,
variables() {
return {
contextNamespacePath: this.fullPath,
refs: [this.searchTerm],
};
},
skip() {
return !this.isSearchingByReference;
},
update(data) {
return data?.workItemsByReference?.nodes || [];
},
error() {
this.$emit('error', this.$options.i18n.workItemsFetchError);
},
},
},
methods: {
searchWorkItems(searchTerm) {
this.search = searchTerm;
searchWorkItems(value) {
this.searchTerm = value;
this.searchStarted = true;
},
async updateParent() {
@ -191,7 +220,7 @@ export default {
handleItemClick(item) {
this.localSelectedItem = item;
this.searchStarted = false;
this.search = '';
this.searchTerm = '';
this.updateParent();
},
unassignParent() {
@ -203,7 +232,7 @@ export default {
},
onListboxHide() {
this.searchStarted = false;
this.search = '';
this.searchTerm = '';
},
},
};

View File

@ -422,8 +422,6 @@ module WikiActions
end
def find_redirection(path, redirect_limit = 50)
return unless Feature.enabled?(:wiki_redirection, container)
seen = Set[]
current_path = path

View File

@ -6,6 +6,7 @@ module Groups
before_action :handle_new_work_item_path, only: [:show]
before_action do
push_frontend_feature_flag(:comment_tooltips)
push_frontend_feature_flag(:notifications_todos_buttons)
push_force_frontend_feature_flag(:work_items, group&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_beta, group&.work_items_beta_feature_flag_enabled?)

View File

@ -49,6 +49,7 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:service_desk_ticket)
push_frontend_feature_flag(:issues_list_drawer, project)
push_frontend_feature_flag(:notifications_todos_buttons, current_user)
push_frontend_feature_flag(:comment_tooltips, current_user)
end
before_action only: [:index, :show] do

View File

@ -13,6 +13,7 @@ class Projects::WorkItemsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items_beta, project&.work_items_beta_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_alpha, project&.work_items_alpha_feature_flag_enabled?)
push_frontend_feature_flag(:namespace_level_work_items, project&.group)
push_frontend_feature_flag(:comment_tooltips)
end
feature_category :team_planning

View File

@ -69,7 +69,7 @@ module DiffHelper
if rapid_diffs?
expand_button = content_tag(:button, '...', class: 'gl-bg-none gl-border-0 gl-p-0', data: { visible_when_loading: false, **expand_data })
spinner = render(Pajamas::SpinnerComponent.new(size: :sm, class: 'gl-display-none gl-text-align-right', data: { visible_when_loading: true }))
spinner = render(Pajamas::SpinnerComponent.new(size: :sm, class: 'gl-hidden gl-text-align-right', data: { visible_when_loading: true }))
expand_html = content_tag(:div, [expand_button, spinner].join.html_safe, data: { expand_wrapper: true })
else
expand_html = '...'

View File

@ -30,6 +30,7 @@ module Projects::ProjectMembersHelper
can_manage_access_requests: Ability.allowed?(current_user, :admin_member_access_request, project),
group_name: project.group&.name,
group_path: project.group&.full_path,
project_path: project.full_path,
can_approve_access_requests: true, # true for CE, overridden in EE
available_roles: available_project_roles(project)
}

View File

@ -444,7 +444,7 @@ class Wiki
private
def update_redirection_actions(new_path, old_path = nil, **options)
return [] unless Feature.enabled?(:wiki_redirection, container) && old_path != new_path
return [] unless old_path != new_path
old_contents = repository.blob_at(default_branch, REDIRECTS_YML)
redirects = old_contents ? YAML.safe_load(old_contents.data).to_h : {}

View File

@ -143,6 +143,10 @@ class WorkItem < Issue
hierarchy.ancestors(hierarchy_order: :asc)
end
def descendants
hierarchy.descendants
end
def same_type_base_and_ancestors
hierarchy(same_type: true).base_and_ancestors(hierarchy_order: :asc)
end

View File

@ -4,7 +4,8 @@ module Packages
class CreateEventService < BaseService
INTERNAL_EVENTS_NAMES = {
'delete_package' => 'delete_package_from_registry',
'pull_package' => 'pull_package_from_registry'
'pull_package' => 'pull_package_from_registry',
'push_package' => 'push_package_to_registry'
}.freeze
def execute

View File

@ -10,7 +10,7 @@
checkbox_options: { class: 'js-deny-all-requests' }
= render Pajamas::AlertComponent.new(variant: :warning,
dismissible: false,
alert_options: { class: "gl-mb-3 js-deny-all-requests-warning #{'gl-display-none' unless deny_all_requests}" }) do |c|
alert_options: { class: "gl-mb-3 js-deny-all-requests-warning #{'gl-hidden' unless deny_all_requests}" }) do |c|
- c.with_body do
= s_('OutboundRequests|Webhooks and integrations might not work properly. GitLab Duo will not work unless `cloud.gitlab.com` is in the following allowlist.')
= f.gitlab_ui_checkbox_component :allow_local_requests_from_web_hooks_and_services,

View File

@ -24,12 +24,12 @@
.form-text.gl-pl-6.gl-mb-6
- if @service_ping_data.present?
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-payload-preview-trigger gl-mr-2', data: { payload_selector: ".#{payload_class}" } }) do
= gl_loading_icon(css_class: 'js-spinner gl-display-none', inline: true)
= gl_loading_icon(css_class: 'js-spinner gl-hidden', inline: true)
%span.js-text.gl-display-inline= s_('AdminSettings|Preview payload')
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-payload-download-trigger gl-mr-2', data: { endpoint: usage_data_admin_application_settings_path(format: :json) } }) do
= gl_loading_icon(css_class: 'js-spinner gl-display-none', inline: true)
= gl_loading_icon(css_class: 'js-spinner gl-hidden', inline: true)
%span.js-text.gl-display-inline= s_('AdminSettings|Download payload')
%pre.js-syntax-highlight.code.highlight.gl-mt-2.gl-display-none{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
%pre.js-syntax-highlight.code.highlight.gl-mt-2.gl-hidden{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
- else
= render Pajamas::AlertComponent.new(variant: :warning,
dismissible: false,

View File

@ -22,7 +22,7 @@
= render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-toggle-button js-toggle-content', data: { testid: 'add-new-token-button' } }) do
= _('Add new token')
- c.with_body do
.gl-new-card-add-form.gl-mt-3.gl-display-none.js-toggle-content.js-add-new-token-form
.gl-new-card-add-form.gl-mt-3.gl-hidden.js-toggle-content.js-add-new-token-form
= render 'shared/access_tokens/form',
ajax: true,
type: type,

View File

@ -40,7 +40,7 @@
= _('Add new token')
- c.with_body do
- if current_user.can?(:create_resource_access_tokens, @group)
.gl-new-card-add-form.gl-mt-3.gl-display-none.js-toggle-content.js-add-new-token-form
.gl-new-card-add-form.gl-mt-3.gl-hidden.js-toggle-content.js-add-new-token-form
= render 'shared/access_tokens/form',
ajax: true,
type: type,

View File

@ -2,7 +2,7 @@
- submit_button_options = { type: :submit, variant: :confirm, button_options: { id: 'commit-changes', class: 'js-commit-button', data: { testid: 'commit-button' } } }
= render Pajamas::ButtonComponent.new(**submit_button_options) do
= _('Commit changes')
= render Pajamas::ButtonComponent.new(loading: true, disabled: true, **submit_button_options.merge({ button_options: { class: 'js-commit-button-loading gl-display-none' } })) do
= render Pajamas::ButtonComponent.new(loading: true, disabled: true, **submit_button_options.merge({ button_options: { class: 'js-commit-button-loading gl-hidden' } })) do
= _('Commit changes')
= render Pajamas::ButtonComponent.new(href: cancel_path, button_options: { class: 'gl-ml-3', id: 'cancel-changes', aria: { label: _('Discard changes') }, data: { confirm: leave_edit_message, confirm_btn_variant: "danger" } }) do

View File

@ -13,7 +13,7 @@
= f.text_field :name, placeholder: "My awesome project", class: "form-control gl-form-input input-lg", data: { testid: 'project-name', track_label: "#{track_label}", track_action: "activate_form_input", track_property: "project_name", track_value: "" }, required: true, aria: { required: true }
%small#js-project-name-description.form-text.gl-text-secondary
= s_("ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces.")
#js-project-name-error.gl-field-error.gl-mt-2.gl-display-none
#js-project-name-error.gl-field-error.gl-mt-2.gl-hidden
.form-group.gl-form-group.gl-w-full.gl-display-flex.gl-flex-wrap
.form-group.project-path.col-sm-6.gl-pr-0
= f.label :namespace_id, class: 'label-bold' do
@ -38,9 +38,9 @@
= f.label :path, class: 'label-bold' do
%span= _("Project slug")
= f.text_field :path, placeholder: "my-awesome-project", class: "form-control gl-form-input", required: true, aria: { required: true }, data: { testid: 'project-path', username: current_user.username }
.js-group-namespace-error.gl-my-3.gl-text-red-500.gl-display-none.col-12
.js-group-namespace-error.gl-my-3.gl-text-red-500.gl-hidden.col-12
= s_('ProjectsNew|Pick a group or namespace where you want to create this project.')
.js-user-readme-repo.gl-my-3.gl-display-none.col-12
.js-user-readme-repo.gl-my-3.gl-hidden.col-12
= render Pajamas::AlertComponent.new(dismissible: false,
variant: :success) do |c|
- c.with_body do

View File

@ -13,7 +13,7 @@
.home-panel-description-markdown.read-more-container{ itemprop: 'description', data: { 'read-more-height': 320 } }
.read-more-content.read-more-content--has-scrim
= markdown_field(@project, :description)
.js-read-more-trigger.gl-display-none.gl-w-full.gl-h-8.gl-absolute.gl-bottom-0.gl-z-2.gl-bg-default
.js-read-more-trigger.gl-hidden.gl-w-full.gl-h-8.gl-absolute.gl-bottom-0.gl-z-2.gl-bg-default
= render Pajamas::ButtonComponent.new(variant: :link, button_options: { 'aria-label': _("Expand project information") }) do
= sprite_icon('chevron-down', size: 14)
= _("Read more")

View File

@ -1,7 +1,7 @@
- if local_assigns.fetch(:show_toggle, true)
%span.diff-toggle-caret
= sprite_icon('chevron-right', css_class: 'chevron-right gl-display-none')
= sprite_icon('chevron-down', css_class: 'chevron-down gl-display-none')
= sprite_icon('chevron-right', css_class: 'chevron-right gl-hidden')
= sprite_icon('chevron-down', css_class: 'chevron-down gl-hidden')
- if diff_file.submodule?
%span

View File

@ -14,7 +14,7 @@
.wrap
.frame.deleted
= image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
%p.image-info.gl-display-none
%p.image-info.gl-hidden
%span.meta-filesize= number_to_human_size(old_blob.size)
|
%strong W:
@ -24,7 +24,7 @@
%span.meta-height
.wrap
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
%p.image-info.gl-display-none
%p.image-info.gl-hidden
%span.meta-filesize= number_to_human_size(blob.size)
|
%strong W:
@ -33,7 +33,7 @@
%strong H:
%span.meta-height
.swipe.view.gl-display-none
.swipe.view.gl-hidden
.swipe-frame
.frame.deleted.old-diff
= image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
@ -43,7 +43,7 @@
%span.top-handle
%span.bottom-handle
.onion-skin.view.gl-display-none
.onion-skin.view.gl-hidden
.onion-skin-frame
.frame.deleted
= image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
@ -54,7 +54,7 @@
.dragger{ :style => "left: 0px;" }
.opaque
.view-modes.gl-display-none
.view-modes.gl-hidden
%ul.view-modes-menu
%li.two-up{ data: { mode: 'two-up' } } 2-up
%li.swipe{ data: { mode: 'swipe' } } Swipe

View File

@ -4,7 +4,7 @@
.form-group.js-ssh-host-keys-section{ class: ('collapse' unless mirror.ssh_mirror_url?) }
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-detect-host-keys gl-mr-3', data: { testid: 'detect-host-keys' } }) do
= gl_loading_icon(inline: true, css_class: 'js-spinner gl-display-none gl-mr-2')
= gl_loading_icon(inline: true, css_class: 'js-spinner gl-hidden gl-mr-2')
= _('Detect host keys')
.fingerprint-ssh-info.js-fingerprint-ssh-info.gl-mt-3.gl-mb-3{ class: ('collapse' unless mirror.ssh_mirror_url?) }
%label.label-bold

View File

@ -39,7 +39,7 @@
= _('Add new token')
- c.with_body do
- if current_user.can?(:create_resource_access_tokens, @project)
.gl-new-card-add-form.gl-mt-3.gl-display-none.js-toggle-content.js-add-new-token-form
.gl-new-card-add-form.gl-mt-3.gl-hidden.js-toggle-content.js-add-new-token-form
= render_if_exists 'projects/settings/access_tokens/form', type: type
#js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_access_tokens.to_json, no_active_tokens_message: _('This project has no active access tokens.'), show_role: true } }

View File

@ -4,7 +4,7 @@
- if @default_integration
.js-vue-default-integration-settings{ data: integration_form_data(@default_integration, group: @group, project: @project) }
.js-vue-integration-settings{ data: integration_form_data(integration, group: @group, project: @project) }
.js-integration-help-html.gl-display-none
.js-integration-help-html.gl-hidden
-# All content below will be repositioned in Vue
- if lookup_context.template_exists?('help', "shared/integrations/#{integration.to_param}", true)
= render "shared/integrations/#{integration.to_param}/help", integration: integration

View File

@ -29,11 +29,11 @@
= markdown_toolbar_button({ icon: "list-numbered", css_class: 'haml-markdown-button gl-mr-3', data: { "md-tag" => "1. ", "md-prepend" => true }, title: _("Add a numbered list") })
= markdown_toolbar_button({ icon: "list-task", css_class: 'haml-markdown-button gl-mr-3', data: { "md-tag" => "- [ ] ", "md-prepend" => true }, title: _("Add a checklist") })
= markdown_toolbar_button({ icon: "list-indent",
css_class: 'gl-display-none gl-mr-3',
css_class: 'gl-hidden gl-mr-3',
data: { "md-command" => 'indentLines', "md-shortcuts": '["mod+]"]' },
title: sprintf(s_("MarkdownEditor|Indent line (%{modifier_key}])") % { modifier_key: modifier_key }) })
= markdown_toolbar_button({ icon: "list-outdent",
css_class: 'gl-display-none gl-mr-3',
css_class: 'gl-hidden gl-mr-3',
data: { "md-command" => 'outdentLines', "md-shortcuts": '["mod+["]' },
title: sprintf(s_("MarkdownEditor|Outdent line (%{modifier_key}[)") % { modifier_key: modifier_key }) })
= markdown_toolbar_button({ icon: "details-block",

View File

@ -41,7 +41,7 @@
= _("Requested %{time_ago}").html_safe % { time_ago: time_ago_with_tooltip(member.requested_at) }
- else
= _("Given access %{time_ago}").html_safe % { time_ago: time_ago_with_tooltip(member.created_at) }
%span.js-expires-in{ class: ('gl-display-none' unless member.expires?) }
%span.js-expires-in{ class: ('gl-hidden' unless member.expires?) }
&middot;
%span.js-expires-in-text{ class: "has-tooltip#{' text-warning' if member.expires_soon?}", title: (member.expires_at.to_time.in_time_zone.to_fs(:medium) if member.expires?) }
- if member.expires?

View File

@ -68,7 +68,7 @@
.system-note-commit-list-toggler.hide
= _("Toggle commit list")
= sprite_icon('chevron-down', css_class: 'js-chevron-down gl-ml-1 gl-vertical-align-text-bottom')
= sprite_icon('chevron-up', css_class: 'js-chevron-up gl-ml-1 gl-vertical-align-text-bottom gl-display-none')
= sprite_icon('chevron-up', css_class: 'js-chevron-up gl-ml-1 gl-vertical-align-text-bottom gl-hidden')
- if note.attachment.url
.note-attachment
- if note.attachment.image?

View File

@ -17,39 +17,33 @@
= wiki_sidebar_toggle_button
.prepend-top-default.gl-mb-3
= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card gl-mt-0 gl-mb-5' }, header_options: { class: 'gl-new-card-header gl-border-b-0' }, body_options: { class: 'gl-new-card-body gl-px-0' }) do |c|
- c.with_header do
.gl-new-card-title-wrapper.gl-flex-col
%h3.gl-new-card-title
= _('Versions')
.gl-new-card-count
= sprite_icon('history', css_class: 'gl-mr-2')
= @commits_count
- c.with_body do
.table-holder{ data: { testid: 'wiki-history-table' } }
%table.table.wiki-history{ class: '!gl-mb-0' }
%thead
= render ::Layouts::CrudComponent.new(_('Versions'),
icon: 'history',
count: @commits_count) do |c|
- c.with_body do
.table-holder{ data: { testid: 'wiki-history-table' } }
%table.table.b-table.gl-table.b-table-stacked-sm.-gl-mt-1.-gl-mb-2.wiki-history
%thead.gl-hidden.md:gl-table-header-group
%tr
%th= _('Version')
%th= _('Author')
%th= _('Diff')
%th= _('Last updated')
%tbody
- @commits.each_with_index do |commit, i|
%tr
%th= _('Version')
%th= _('Author')
%th= _('Diff')
%th= _('Last updated')
%tbody
- @commits.each_with_index do |commit, i|
%tr
%td
= link_to wiki_page_path(@wiki, @page, version_id: commit.id) do
v#{@commits_count - i}
%td
= commit.author_name
%td
.commit-content
= link_to wiki_page_path(@wiki, @page, action: :diff, version_id: commit.id), { title: commit.message } do
= commit.message
%td
= time_ago_with_tooltip(commit.authored_date)
= paginate @commits, theme: 'gitlab'
%td{ data: { label: _('Version') } }
= link_to wiki_page_path(@wiki, @page, version_id: commit.id) do
v#{@commits_count - i}
%td{ data: { label: _('Author') } }
= commit.author_name
%td{ data: { label: _('Diff') } }
.commit-content
= link_to wiki_page_path(@wiki, @page, action: :diff, version_id: commit.id), { title: commit.message } do
= commit.message
%td{ data: { label: _('Last updated') } }
= time_ago_with_tooltip(commit.authored_date)
- c.with_pagination do
= paginate @commits, theme: 'gitlab'
= render 'shared/wikis/sidebar'

View File

@ -28,7 +28,7 @@
= render Pajamas::ButtonComponent.new(size: :small, button_options: { class: 'js-toggle-button js-toggle-content', data: { testid: 'add-new-token-button' } }) do
= _('Add new token')
- c.with_body do
.gl-new-card-add-form.gl-mt-3.gl-display-none.js-toggle-content.js-add-new-token-form
.gl-new-card-add-form.gl-mt-3.gl-hidden.js-toggle-content.js-add-new-token-form
= render 'shared/access_tokens/form',
ajax: true,
type: type,

View File

@ -1,8 +1,8 @@
- page_title _('SSH Keys')
- add_page_specific_style 'page_bundles/profile'
- @force_desktop_expanded_sidebar = true
- add_form_class = 'gl-display-none' if !form_errors(@key)
- hide_class = 'gl-display-none' if form_errors(@key)
- add_form_class = 'gl-hidden' if !form_errors(@key)
- hide_class = 'gl-hidden' if form_errors(@key)
.settings-section.js-search-settings-section
.settings-sticky-header

View File

@ -0,0 +1,23 @@
---
description: Packaged pushed to the registry
internal_events: true
action: push_package_to_registry
identifiers:
- project
- namespace
- user
additional_properties:
label:
description: The name of the package type
property:
description: The auth type. Either 'guest', 'user' or 'deploy_token'
product_group: package_registry
milestone: '17.3'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/161199
distributions:
- ce
- ee
tiers:
- free
- premium
- ultimate

View File

@ -1,8 +1,8 @@
---
name: wiki_redirection
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150727
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/460097
milestone: '17.1'
name: comment_tooltips
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/158020
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/476395
milestone: '17.3'
type: development
group: group::knowledge
default_enabled: true
group: group::project management
default_enabled: false

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_composer_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: composer
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_conan_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: conan
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_generic_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: generic
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_golang_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: golang
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_maven_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: maven
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_npm_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: npm
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_nuget_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: nuget
distribution:
- ee
- ce

View File

@ -6,11 +6,9 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_push_package
data_source: internal_events
events:
- name: push_package_to_registry
distribution:
- ee
- ce

View File

@ -7,11 +7,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_push_package_by_deploy_token
data_source: internal_events
events:
- name: push_package_to_registry
filter:
property: deploy_token
distribution:
- ee
- ce

View File

@ -7,11 +7,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_push_package_by_guest
data_source: internal_events
events:
- name: push_package_to_registry
filter:
property: guest
distribution:
- ee
- ce

View File

@ -7,11 +7,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_push_package_by_user
data_source: internal_events
events:
- name: push_package_to_registry
filter:
property: user
distribution:
- ee
- ce

View File

@ -6,11 +6,11 @@ product_group: package_registry
value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_pypi_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: pypi
distribution:
- ee
- ce

View File

@ -8,11 +8,11 @@ status: active
time_frame: all
milestone: '13.10'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/53480
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_rubygems_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: rubygems
distribution:
- ce
- ee

View File

@ -8,11 +8,11 @@ status: active
milestone: '13.11'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55018
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_terraform_module_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: terraform_module
distribution:
- ce
- ee

View File

@ -7,11 +7,11 @@ status: active
milestone: "14.1"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64814
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_helm_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: helm
data_category: optional
distribution:
- ce

View File

@ -8,11 +8,11 @@ status: active
milestone: '15.6'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97133
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: package_events
event: i_package_rpm_push_package
data_source: internal_events
events:
- name: push_package_to_registry
filter:
label: rpm
distribution:
- ce
- ee

View File

@ -7,7 +7,7 @@
}
},
"then": {
"oneOf": [
"anyOf": [
{
"properties": {
"instrumentation_class": {
@ -43,23 +43,9 @@
},
{
"properties": {
"key_path": {
"status": {
"description": "Legacy metrics that do not match with the schema",
"enum": [
"counts.dependency_list_usages_total",
"counts.network_policy_forwards",
"counts.network_policy_drops",
"counts.static_site_editor_views",
"counts.static_site_editor_commits",
"counts.static_site_editor_merge_requests",
"counts.package_events_i_package_container_delete_package",
"counts.package_events_i_package_container_pull_package",
"counts.package_events_i_package_container_push_package",
"counts.package_events_i_package_debian_push_package",
"counts.package_events_i_package_tag_delete_package",
"counts.package_events_i_package_tag_pull_package",
"counts.package_events_i_package_tag_push_package"
]
"const": "removed"
}
}
}

View File

@ -4,7 +4,7 @@ group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
## Troubleshooting project import and export
# Troubleshooting project import and export
If you are having trouble with import or export, use a Rake task to enable debug mode:
@ -18,11 +18,11 @@ EXPORT_DEBUG=true gitlab-rake "gitlab:import_export:export[root, group/subgroup,
Then, review the following details on specific error messages.
### `Exception: undefined method 'name' for nil:NilClass`
## `Exception: undefined method 'name' for nil:NilClass`
The `username` is not valid.
### `Exception: undefined method 'full_path' for nil:NilClass`
## `Exception: undefined method 'full_path' for nil:NilClass`
The `namespace_path` does not exist.
For example, one of the groups or subgroups is mistyped or missing,
@ -31,11 +31,11 @@ or you've specified the project name in the path.
The task only creates the project.
If you want to import it to a new group or subgroup, create it first.
### `Exception: No such file or directory @ rb_sysopen - (filename)`
## `Exception: No such file or directory @ rb_sysopen - (filename)`
The specified project export file in `archive_path` is missing.
### `Exception: Permission denied @ rb_sysopen - (filename)`
## `Exception: Permission denied @ rb_sysopen - (filename)`
The specified project export file cannot be accessed by the `git` user.
@ -45,7 +45,7 @@ To fix the issue:
1. Change the file permissions to `0400`.
1. Move the file to a public folder (for example `/tmp/`).
### `Name can contain only letters, digits, emoji ...`
## `Name can contain only letters, digits, emoji ...`
```plaintext
Name can contain only letters, digits, emoji, '_', '.', '+', dashes, or spaces. It must start with a letter,
@ -58,11 +58,11 @@ The project name specified in `project_path` is not valid for one of the specifi
Only put the project name in `project_path`. For example, if you provide a path of subgroups
it fails with this error as `/` is not a valid character in a project name.
### `Name has already been taken and Path has already been taken`
## `Name has already been taken and Path has already been taken`
A project with that name already exists.
### `Exception: Error importing repository into (namespace) - No space left on device`
## `Exception: Error importing repository into (namespace) - No space left on device`
The disk has insufficient space to complete the import.
@ -70,7 +70,7 @@ During import, the tarball is cached in your configured `shared_path` directory.
disk has enough free space to accommodate both the cached tarball and the unpacked
project files on disk.
### Import succeeds with `Total number of not imported relations: XX` message
## Import succeeds with `Total number of not imported relations: XX` message
If you receive a `Total number of not imported relations: XX` message, and issues
aren't created during the import, check [exceptions_json.log](../logs/index.md#exceptions_jsonlog).
@ -89,7 +89,7 @@ Issue.where(project_id: Project.find(ID).root_namespace.all_projects).maximum(:r
Repeat the import attempt and check if the issues are imported successfully.
### Gitaly calls error when importing
## Gitaly calls error when importing
If you're attempting to import a large project into a development environment, Gitaly might throw an error about too many calls or invocations. For example:

View File

@ -24,7 +24,16 @@ For an overview, see [Project Dependency](https://www.youtube.com/watch?v=ckqkn9
## Prerequisites
To view your project's dependencies, ensure you meet the following requirements:
To list your project's dependencies the SBOM document must:
- Comply with [the CycloneDX specification](https://github.com/CycloneDX/specification) version `1.4` or `1.5`.
- Be uploaded as [a CI/CD artifact report](../../../ci/yaml/artifacts_reports.md#artifactsreportscyclonedx) from a successful pipeline on the default branch.
NOTE:
Although this is not mandatory for the dependency list, some security features also require the
document to include and comply with the [GitLab CycloneDX property taxonomy](../../../development/sec/cyclonedx_property_taxonomy.md).
GitLab already generates this document when the following requirements are met:
- The [Dependency Scanning](../dependency_scanning/index.md)
or [Container Scanning](../container_scanning/index.md)

View File

@ -191,7 +191,7 @@ DETAILS:
**Status:** Experiment
- Help resolve a vulnerability by generating a merge request that addresses it.
- LLM: Anthropic [Claude 3.5 Sonnet`](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet).
- LLM: Anthropic [Claude 3.5 Sonnet](https://console.cloud.google.com/vertex-ai/publishers/anthropic/model-garden/claude-3-5-sonnet).
- [View documentation](../application_security/vulnerabilities/index.md#vulnerability-resolution).
### Product Analytics

View File

@ -36,9 +36,6 @@ associated with a group rather than a project or user.
In self-managed instances, group access tokens are subject to the same [maximum lifetime limits](../../../administration/settings/account_and_limit_settings.md#limit-the-lifetime-of-access-tokens) as personal access tokens if the limit is set.
WARNING:
The ability to create group access tokens without an expiry date was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. In GitLab 16.0 and later, existing group access tokens without an expiry date are automatically given an expiry date 365 days later than the current date. The automatic adding of an expiry date occurs on GitLab.com during the 16.0 milestone. The automatic adding of an expiry date occurs on self-managed instances when they are upgraded to GitLab 16.0. This change is a breaking change.
You cannot use group access tokens to create other group, project, or personal access tokens.
Group access tokens inherit the [default prefix setting](../../../administration/settings/account_and_limit_settings.md#personal-access-token-prefix)
@ -50,9 +47,7 @@ configured for personal access tokens.
> - Ability to create non-expiring group access tokens [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0.
WARNING:
Project access tokens are treated as [internal users](../../../development/internal_users.md).
If an internal user creates a project access token, that token is able to access
all projects that have visibility level set to [Internal](../../public_access.md).
The ability to create group access tokens without an expiry date was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. For more information on expiry dates added to existing tokens, see the documentation on [access token expiration](#access-token-expiration).
To create a group access token:
@ -71,6 +66,11 @@ To create a group access token:
A group access token is displayed. Save the group access token somewhere safe. After you leave or refresh the page, you can't view it again.
WARNING:
Group access tokens are treated as [internal users](../../../development/internal_users.md).
If an internal user creates a group access token, that token is able to access
all projects that have visibility level set to [Internal](../../public_access.md).
## Create a group access token using Rails console
If you are an administrator, you can create group access tokens in the Rails console:
@ -188,6 +188,40 @@ To enable or disable group access token creation for all subgroups in a top-leve
Even when creation is disabled, you can still use and revoke existing group access tokens.
## Access token expiration
Whether your existing group access tokens have expiry dates automatically applied
depends on what GitLab offering you have, and when you upgraded to GitLab 16.0 or later:
- On GitLab.com, during the 16.0 milestone, existing group access tokens without
an expiry date were automatically given an expiry date of 365 days later than the current date.
- On GitLab self-managed, if you upgraded from GitLab 15.11 or earlier to GitLab 16.0 or later:
- On or before July 23, 2024, existing group access tokens without an expiry
date were automatically given an expiry date of 365 days later than the current date.
This change is a breaking change.
- On or after July 24, 2024, existing group access tokens without an expiry
date did not have an expiry date set.
On GitLab self-managed, if you do a new install of one of the following GitLab
versions, your existing group access tokens do not have expiry dates
automatically applied:
- 16.0.9
- 16.1.7
- 16.2.10
- 16.3.8
- 16.4.6
- 16.5.9
- 16.6.9
- 16.7.9
- 16.8.9
- 16.9.10
- 16.10.9
- 16.11.7
- 17.0.5
- 17.1.3
- 17.2.1
## Bot users for groups
Bot users for groups are [GitLab-created non-billable users](../../../subscriptions/self_managed/index.md#billable-users).

View File

@ -50,6 +50,8 @@ You can use GitLab Flavored Markdown in the following areas:
You can also use other rich text files in GitLab. You might have to install a dependency
to do so. For more information, see the [`gitlab-markup` gem project](https://gitlab.com/gitlab-org/gitlab-markup).
Support for improvements to Markdown preview when using GitLab Flavored Markdown in the Web IDE is proposed in [issue 645](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/645).
### Differences between GitLab Flavored Markdown and standard Markdown
<!--
@ -2077,6 +2079,21 @@ To update the rendered references if the assignee, milestone, or health status c
Issue [420807](https://gitlab.com/gitlab-org/gitlab/-/issues/420807) tracks improving how these
references refresh.
### Show comment preview when hovering on a link
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/29663) in GitLab 17.3 [with a flag](../administration/feature_flags.md) named `comment_tooltips`. Disabled by default.
FLAG:
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
When this feature is enabled, hovering over a link to a comment shows the author and
part of the comment.
When this feature is disabled, hovering over a link to a comment shows information about the item,
such as issue or epic.
### Embedding Observability dashboards
You can embed GitLab Observability UI dashboards descriptions and comments, for example in epics, issues, and MRs.

View File

@ -17,9 +17,6 @@ Personal access tokens can be an alternative to [OAuth2](../../api/oauth2.md) an
In both cases, you authenticate with a personal access token in place of your password.
WARNING:
The ability to create personal access tokens without expiry was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. In GitLab 16.0 and later, existing personal access tokens without an expiry date are automatically given an expiry date of 365 days later than the current date. The automatic adding of an expiry date occurs on GitLab.com during the 16.0 milestone. The automatic adding of an expiry date occurs on self-managed instances when they are upgraded to GitLab 16.0. This change is a breaking change.
Personal access tokens are:
- Required when [two-factor authentication (2FA)](account/two_factor_authentication.md) or
@ -45,6 +42,9 @@ Use impersonation tokens to automate authentication as a specific user.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348660) in GitLab 15.3, default expiration of 30 days is populated in the UI.
> - Ability to create non-expiring personal access tokens [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0.
WARNING:
The ability to create personal access tokens without an expiry date was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. For more information, see the documentation on [when personal access tokens expire](#when-personal-access-tokens-expire).
You can create as many personal access tokens as you like.
1. On the left sidebar, select your avatar.
@ -97,6 +97,9 @@ Prerequisites:
In GitLab 15.7 and later, you can [use the application settings API to disable personal access tokens](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
NOTE:
After you have used the API to disable personal access tokens, those tokens cannot be used in subsequent API calls to manage this setting. To re-enable personal access tokens, you must use the [GitLab Rails console](../../administration/operations/rails_console.md). You can also upgrade to GitLab 17.3 or later so you can use the Admin UI instead.
In GitLab 17.3 and later, you can disable personal access tokens in the Admin UI:
1. On the left sidebar, at the bottom, select **Admin**.
@ -193,6 +196,38 @@ Personal access tokens expire on the date you define, at midnight, 00:00 AM UTC.
[maximum allowed lifetime for the token](../../administration/settings/account_and_limit_settings.md#limit-the-lifetime-of-access-tokens).
If the maximum allowed lifetime is not set, the default expiry date is 365 days from the date of creation.
Whether your existing personal access tokens have expiry dates automatically applied
depends on what GitLab offering you have, and when you upgraded to GitLab 16.0 or later:
- On GitLab.com, during the 16.0 milestone, existing personal access tokens without
an expiry date were automatically given an expiry date of 365 days later than the current date.
- On GitLab self-managed, if you upgraded from GitLab 15.11 or earlier to GitLab 16.0 or later:
- On or before July 23, 2024, existing personal access tokens without an expiry
date were automatically given an expiry date of 365 days later than the current date.
This change is a breaking change.
- On or after July 24, 2024, existing personal access tokens without an expiry
date did not have an expiry date set.
On GitLab self-managed, if you do a new install of one of the following GitLab
versions, your existing personal access tokens do not have expiry dates
automatically applied:
- 16.0.9
- 16.1.7
- 16.2.10
- 16.3.8
- 16.4.6
- 16.5.9
- 16.6.9
- 16.7.9
- 16.8.9
- 16.9.10
- 16.10.9
- 16.11.7
- 17.0.5
- 17.1.3
- 17.2.1
### Personal access token expiry calendar
You can subscribe to an iCalendar endpoint which contains events at the expiry date for each token. After signing in, this endpoint is available at `/-/user_settings/personal_access_tokens.ics`.

View File

@ -104,6 +104,8 @@ For use cases and best practices, follow the [GitLab Duo examples documentation]
#### Use open tabs as context
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/464767) in GitLab 17.2 [with a flag](../../../../administration/feature_flags.md) named `advanced_context_resolver`. Disabled by default.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/462750) in GitLab 17.2 [with a flag](../../../../administration/feature_flags.md) named `code_suggestions_context`. Disabled by default.
> - [Introduced](https://gitlab.com/gitlab-org/editor-extensions/gitlab-lsp/-/issues/276) in GitLab VS Code Extension 4.20.0.
> - [Introduced](https://gitlab.com/gitlab-org/editor-extensions/gitlab-jetbrains-plugin/-/issues/462) in GitLab Duo for JetBrains 2.7.0.
> - [Added](https://gitlab.com/gitlab-org/editor-extensions/gitlab.vim/-/merge_requests/152) to the GitLab Neovim plugin on July 16, 2024.

View File

@ -26,9 +26,6 @@ and [personal access tokens](../../profile/personal_access_tokens.md), but proje
In self-managed instances, project access tokens are subject to the same [maximum lifetime limits](../../../administration/settings/account_and_limit_settings.md#limit-the-lifetime-of-access-tokens) as personal access tokens if the limit is set.
WARNING:
The ability to create project access tokens without expiry was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. In GitLab 16.0 and later, existing project access tokens without an expiry date are automatically given an expiry date of 365 days later than the current date. The automatic adding of an expiry date occurs on GitLab.com during the 16.0 milestone. The automatic adding of an expiry date occurs on self-managed instances when they are upgraded to GitLab 16.0. This change is a breaking change.
You can use project access tokens:
- On GitLab SaaS: If you have the Premium or Ultimate license tier, only one project access token is available with a [trial license](https://about.gitlab.com/free-trial/).
@ -47,9 +44,7 @@ configured for personal access tokens.
> - Ability to create non-expiring project access tokens [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0.
WARNING:
Project access tokens are treated as [internal users](../../../development/internal_users.md).
If an internal user creates a project access token, that token is able to access
all projects that have visibility level set to [Internal](../../public_access.md).
The ability to create project access tokens without an expiry date was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369122) in GitLab 15.4 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/392855) in GitLab 16.0. For more information on expiry dates added to existing tokens, see the documentation on [access token expiration](#access-token-expiration).
To create a project access token:
@ -68,6 +63,11 @@ To create a project access token:
A project access token is displayed. Save the project access token somewhere safe. After you leave or refresh the page, you can't view it again.
WARNING:
Project access tokens are treated as [internal users](../../../development/internal_users.md).
If an internal user creates a project access token, that token is able to access
all projects that have visibility level set to [Internal](../../public_access.md).
## Revoke a project access token
> - Ability to view revoked tokens [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/462217) in GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `retain_resource_access_token_user_after_revoke`. Disabled by default.
@ -127,6 +127,40 @@ To enable or disable project access token creation for all projects in a top-lev
Even when creation is disabled, you can still use and revoke existing project access tokens.
## Access token expiration
Whether your existing project access tokens have expiry dates automatically applied
depends on what GitLab offering you have, and when you upgraded to GitLab 16.0 or later:
- On GitLab.com, during the 16.0 milestone, existing project access tokens without
an expiry date were automatically given an expiry date of 365 days later than the current date.
- On GitLab self-managed, if you upgraded from GitLab 15.11 or earlier to GitLab 16.0 or later:
- On or before July 23, 2024, existing project access tokens without an expiry
date were automatically given an expiry date of 365 days later than the current date.
This change is a breaking change.
- On or after July 24, 2024, existing project access tokens without an expiry
date did not have an expiry date set.
On GitLab self-managed, if you do a new install of one of the following GitLab
versions, your existing project access tokens do not have expiry dates
automatically applied:
- 16.0.9
- 16.1.7
- 16.2.10
- 16.3.8
- 16.4.6
- 16.5.9
- 16.6.9
- 16.7.9
- 16.8.9
- 16.9.10
- 16.10.9
- 16.11.7
- 17.0.5
- 17.1.3
- 17.2.1
## Bot users for projects
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/462217) in GitLab 17.2 [with a flag](../../../administration/feature_flags.md) named `retain_resource_access_token_user_after_revoke`. Disabled by default. When enabled new bot users are made members with no expiry date and, when the token is later revoked or expires, the bot user is retained. It is not deleted and its records are not moved to the Ghost User.

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