Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
948b3c5ace
commit
48902b7e07
|
|
@ -265,7 +265,7 @@ export default {
|
|||
type="file"
|
||||
accept="image/*"
|
||||
name="avatar_file"
|
||||
class="gl-display-none"
|
||||
class="gl-hidden"
|
||||
@change="selectFile"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export default {
|
|||
},
|
||||
showWarning() {
|
||||
if (this.warningText) {
|
||||
this.warningText.classList.remove('gl-display-none');
|
||||
this.warningText.classList.remove('gl-hidden');
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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}`"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
#import "~/graphql_shared/fragments/author.fragment.graphql"
|
||||
|
||||
query note($id: NoteID!) {
|
||||
note(id: $id) {
|
||||
id
|
||||
author {
|
||||
...Author
|
||||
}
|
||||
bodyFirstLineHtml
|
||||
createdAt
|
||||
internal
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const initDetailsButton = () => {
|
|||
|
||||
if (contentEl) {
|
||||
contentEl.classList.remove('hide');
|
||||
btn.classList.add('gl-display-none');
|
||||
btn.classList.add('gl-hidden');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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?)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = '...'
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 : {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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?) }
|
||||
·
|
||||
%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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue