Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9966836575
commit
5cb0fa35e7
|
|
@ -1,5 +1,4 @@
|
|||
<script>
|
||||
import AWS_LOGO_URL from '@gitlab/svgs/dist/illustrations/logos/aws.svg?url';
|
||||
import DOCKER_LOGO_URL from '@gitlab/svgs/dist/illustrations/third-party-logos/ci_cd-template-logos/docker.png';
|
||||
import KUBERNETES_LOGO_URL from '@gitlab/svgs/dist/illustrations/logos/kubernetes.svg?url';
|
||||
import { GlFormRadioGroup, GlIcon, GlLink } from '@gitlab/ui';
|
||||
|
|
@ -8,7 +7,6 @@ import {
|
|||
LINUX_PLATFORM,
|
||||
MACOS_PLATFORM,
|
||||
WINDOWS_PLATFORM,
|
||||
AWS_PLATFORM,
|
||||
DOCKER_HELP_URL,
|
||||
KUBERNETES_HELP_URL,
|
||||
} from '../constants';
|
||||
|
|
@ -43,8 +41,6 @@ export default {
|
|||
MACOS_PLATFORM,
|
||||
WINDOWS_PLATFORM,
|
||||
|
||||
AWS_PLATFORM,
|
||||
AWS_LOGO_URL,
|
||||
DOCKER_HELP_URL,
|
||||
DOCKER_LOGO_URL,
|
||||
KUBERNETES_HELP_URL,
|
||||
|
|
@ -71,20 +67,6 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gl-mt-3 gl-mb-6">
|
||||
<label>{{ s__('Runners|Cloud templates') }}</label>
|
||||
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
|
||||
<div class="gl-display-flex gl-flex-wrap gl-gap-5">
|
||||
<runner-platforms-radio
|
||||
v-model="model"
|
||||
:image="$options.AWS_LOGO_URL"
|
||||
:value="$options.AWS_PLATFORM"
|
||||
>
|
||||
AWS
|
||||
</runner-platforms-radio>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gl-mt-3 gl-mb-6">
|
||||
<label>{{ s__('Runners|Containers') }}</label>
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,6 @@ export const GROUP_FILTERED_SEARCH_NAMESPACE = 'group_runners';
|
|||
export const LINUX_PLATFORM = 'linux';
|
||||
export const MACOS_PLATFORM = 'osx';
|
||||
export const WINDOWS_PLATFORM = 'windows';
|
||||
export const AWS_PLATFORM = 'aws';
|
||||
|
||||
export const DOWNLOAD_LOCATIONS = {
|
||||
[LINUX_PLATFORM]: [
|
||||
|
|
|
|||
|
|
@ -101,8 +101,10 @@ export default (IssuableTokenKeys, disableTargetBranchFilter = false) => {
|
|||
],
|
||||
};
|
||||
|
||||
IssuableTokenKeys.tokenKeys.splice(3, 0, approvedToken.token);
|
||||
IssuableTokenKeys.conditions.push(...approvedToken.conditions);
|
||||
if (gon.features.mrApprovedFilter) {
|
||||
IssuableTokenKeys.tokenKeys.splice(3, 0, approvedToken.token);
|
||||
IssuableTokenKeys.conditions.push(...approvedToken.conditions);
|
||||
}
|
||||
|
||||
const approvedBy = {
|
||||
token: {
|
||||
|
|
@ -149,7 +151,7 @@ export default (IssuableTokenKeys, disableTargetBranchFilter = false) => {
|
|||
],
|
||||
};
|
||||
|
||||
const tokenPosition = 4;
|
||||
const tokenPosition = gon.features.mrApprovedFilter ? 4 : 3;
|
||||
IssuableTokenKeys.tokenKeys.splice(tokenPosition, 0, approvedBy.token);
|
||||
IssuableTokenKeys.tokenKeysWithAlternative.splice(
|
||||
tokenPosition,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
<script>
|
||||
import {
|
||||
GlButtonGroup,
|
||||
GlButton,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlTooltipDirective,
|
||||
GlModalDirective,
|
||||
} from '@gitlab/ui';
|
||||
import { GlDropdownItem, GlModalDirective } from '@gitlab/ui';
|
||||
import { TYPE_ISSUE } from '~/issues/constants';
|
||||
import { __ } from '~/locale';
|
||||
import CsvExportModal from './csv_export_modal.vue';
|
||||
|
|
@ -17,19 +10,13 @@ export default {
|
|||
exportAsCsvButtonText: __('Export as CSV'),
|
||||
importCsvText: __('Import CSV'),
|
||||
importFromJiraText: __('Import from Jira'),
|
||||
importIssuesText: __('Import issues'),
|
||||
},
|
||||
name: 'CsvImportExportButtons',
|
||||
components: {
|
||||
GlButtonGroup,
|
||||
GlButton,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
CsvExportModal,
|
||||
CsvImportModal,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
GlModal: GlModalDirective,
|
||||
},
|
||||
inject: {
|
||||
|
|
@ -42,18 +29,12 @@ export default {
|
|||
showImportButton: {
|
||||
default: false,
|
||||
},
|
||||
containerClass: {
|
||||
default: '',
|
||||
},
|
||||
canEdit: {
|
||||
default: false,
|
||||
},
|
||||
projectImportJiraPath: {
|
||||
default: null,
|
||||
},
|
||||
showLabel: {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
exportCsvPath: {
|
||||
|
|
@ -74,48 +55,30 @@ export default {
|
|||
importModalId() {
|
||||
return `${this.issuableType}-import-modal`;
|
||||
},
|
||||
importButtonTooltipText() {
|
||||
return this.showLabel ? null : this.$options.i18n.importIssuesText;
|
||||
},
|
||||
importButtonIcon() {
|
||||
return this.showLabel ? null : 'import';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="containerClass">
|
||||
<gl-button-group class="gl-w-full">
|
||||
<gl-button
|
||||
v-if="showExportButton"
|
||||
v-gl-tooltip="$options.i18n.exportAsCsvButtonText"
|
||||
v-gl-modal="exportModalId"
|
||||
icon="export"
|
||||
:aria-label="$options.i18n.exportAsCsvButtonText"
|
||||
data-qa-selector="export_as_csv_button"
|
||||
/>
|
||||
<gl-dropdown
|
||||
v-if="showImportButton"
|
||||
v-gl-tooltip="importButtonTooltipText"
|
||||
data-qa-selector="import_issues_dropdown"
|
||||
:text="$options.i18n.importIssuesText"
|
||||
:text-sr-only="!showLabel"
|
||||
:icon="importButtonIcon"
|
||||
class="gl-w-full gl-md-w-auto"
|
||||
>
|
||||
<gl-dropdown-item v-gl-modal="importModalId">
|
||||
{{ $options.i18n.importCsvText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item
|
||||
v-if="canEdit"
|
||||
:href="projectImportJiraPath"
|
||||
data-qa-selector="import_from_jira_link"
|
||||
>
|
||||
{{ $options.i18n.importFromJiraText }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
</gl-button-group>
|
||||
<ul class="gl-display-contents">
|
||||
<gl-dropdown-item
|
||||
v-if="showExportButton"
|
||||
v-gl-modal="exportModalId"
|
||||
data-qa-selector="export_as_csv_button"
|
||||
>
|
||||
{{ $options.i18n.exportAsCsvButtonText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="showImportButton" v-gl-modal="importModalId">
|
||||
{{ $options.i18n.importCsvText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item
|
||||
v-if="showImportButton && canEdit"
|
||||
:href="projectImportJiraPath"
|
||||
data-qa-selector="import_from_jira_link"
|
||||
>
|
||||
{{ $options.i18n.importFromJiraText }}
|
||||
</gl-dropdown-item>
|
||||
|
||||
<csv-export-modal
|
||||
v-if="showExportButton"
|
||||
:modal-id="exportModalId"
|
||||
|
|
@ -123,5 +86,5 @@ export default {
|
|||
:issuable-count="issuableCount"
|
||||
/>
|
||||
<csv-import-modal v-if="showImportButton" :modal-id="importModalId" />
|
||||
</div>
|
||||
</ul>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -36,11 +36,9 @@ export function initCsvImportExportButtons() {
|
|||
email,
|
||||
exportCsvPath,
|
||||
importCsvIssuesPath,
|
||||
containerClass,
|
||||
canEdit,
|
||||
projectImportJiraPath,
|
||||
maxAttachmentSize,
|
||||
showLabel,
|
||||
} = el.dataset;
|
||||
|
||||
return new Vue({
|
||||
|
|
@ -52,11 +50,9 @@ export function initCsvImportExportButtons() {
|
|||
issuableType,
|
||||
email,
|
||||
importCsvIssuesPath,
|
||||
containerClass,
|
||||
canEdit: parseBoolean(canEdit),
|
||||
projectImportJiraPath,
|
||||
maxAttachmentSize,
|
||||
showLabel,
|
||||
},
|
||||
render: (createElement) =>
|
||||
createElement(CsvImportExportButtons, {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlButton, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { GlButton, GlDropdown, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
import NewResourceDropdown from '~/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue';
|
||||
|
|
@ -12,6 +12,7 @@ export default {
|
|||
components: {
|
||||
CsvImportExportButtons,
|
||||
GlButton,
|
||||
GlDropdown,
|
||||
GlEmptyState,
|
||||
GlLink,
|
||||
GlSprintf,
|
||||
|
|
@ -71,12 +72,19 @@ export default {
|
|||
<gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm">
|
||||
{{ $options.i18n.newIssueLabel }}
|
||||
</gl-button>
|
||||
<csv-import-export-buttons
|
||||
|
||||
<gl-dropdown
|
||||
v-if="showCsvButtons"
|
||||
class="gl-w-full gl-sm-w-auto gl-sm-mr-3"
|
||||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
/>
|
||||
:text="$options.i18n.importIssues"
|
||||
data-qa-selector="import_issues_dropdown"
|
||||
>
|
||||
<csv-import-export-buttons
|
||||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
/>
|
||||
</gl-dropdown>
|
||||
|
||||
<new-resource-dropdown
|
||||
v-if="showNewIssueDropdown"
|
||||
class="gl-align-self-center"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
<script>
|
||||
import { GlButton, GlFilteredSearchToken, GlTooltipDirective } from '@gitlab/ui';
|
||||
import {
|
||||
GlButton,
|
||||
GlFilteredSearchToken,
|
||||
GlTooltipDirective,
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDropdownDivider,
|
||||
} from '@gitlab/ui';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import fuzzaldrinPlus from 'fuzzaldrin-plus';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
|
@ -9,8 +16,8 @@ import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.grap
|
|||
import getIssuesCountsQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql';
|
||||
import { createAlert, VARIANT_INFO } from '~/alert';
|
||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import IssuableByEmail from '~/issuable/components/issuable_by_email.vue';
|
||||
import {
|
||||
STATUS_ALL,
|
||||
|
|
@ -114,6 +121,9 @@ export default {
|
|||
EmptyStateWithAnyIssues,
|
||||
EmptyStateWithoutAnyIssues,
|
||||
GlButton,
|
||||
GlDropdown,
|
||||
GlDropdownDivider,
|
||||
GlDropdownItem,
|
||||
IssuableByEmail,
|
||||
IssuableList,
|
||||
IssueCardStatistics,
|
||||
|
|
@ -801,26 +811,6 @@ export default {
|
|||
@page-size-change="handlePageSizeChange"
|
||||
>
|
||||
<template #nav-actions>
|
||||
<gl-button
|
||||
v-gl-tooltip
|
||||
:href="rssPath"
|
||||
icon="rss"
|
||||
:title="$options.i18n.rssLabel"
|
||||
:aria-label="$options.i18n.rssLabel"
|
||||
/>
|
||||
<gl-button
|
||||
v-gl-tooltip
|
||||
:href="calendarPath"
|
||||
icon="calendar"
|
||||
:title="$options.i18n.calendarLabel"
|
||||
:aria-label="$options.i18n.calendarLabel"
|
||||
/>
|
||||
<csv-import-export-buttons
|
||||
v-if="showCsvButtons"
|
||||
class="gl-md-mr-3"
|
||||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
/>
|
||||
<gl-button
|
||||
v-if="canBulkUpdate"
|
||||
:disabled="isBulkEditButtonDisabled"
|
||||
|
|
@ -842,6 +832,30 @@ export default {
|
|||
:query-variables="newIssueDropdownQueryVariables"
|
||||
:extract-projects="extractProjects"
|
||||
/>
|
||||
<gl-dropdown
|
||||
v-gl-tooltip.hover="$options.i18n.actionsLabel"
|
||||
category="tertiary"
|
||||
icon="ellipsis_v"
|
||||
no-caret
|
||||
:text="$options.i18n.actionsLabel"
|
||||
text-sr-only
|
||||
data-qa-selector="issues_list_more_actions_dropdown"
|
||||
>
|
||||
<csv-import-export-buttons
|
||||
v-if="showCsvButtons"
|
||||
:export-csv-path="exportCsvPathWithQuery"
|
||||
:issuable-count="currentTabCount"
|
||||
/>
|
||||
|
||||
<gl-dropdown-divider v-if="showCsvButtons" />
|
||||
|
||||
<gl-dropdown-item :href="rssPath">
|
||||
{{ $options.i18n.rssLabel }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item :href="calendarPath">
|
||||
{{ $options.i18n.calendarLabel }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
</template>
|
||||
|
||||
<template #timeframe="{ issuable = {} }">
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export const i18n = {
|
|||
editIssues: __('Edit issues'),
|
||||
errorFetchingCounts: __('An error occurred while getting issue counts'),
|
||||
errorFetchingIssues: __('An error occurred while loading issues'),
|
||||
importIssues: __('Import issues'),
|
||||
issueRepositioningMessage: __(
|
||||
'Issues are being rebalanced at the moment, so manual reordering is disabled.',
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
|
||||
import { __, s__ } from '~/locale';
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
|
|
@ -10,38 +10,48 @@ export default {
|
|||
taskActions: s__('WorkItem|Task actions'),
|
||||
},
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlDisclosureDropdown,
|
||||
GlDisclosureDropdownItem,
|
||||
},
|
||||
inject: ['canUpdate'],
|
||||
methods: {
|
||||
convertToTask() {
|
||||
eventHub.$emit('convert-task-list-item', this.$el.closest('li').dataset.sourcepos);
|
||||
this.closeDropdown();
|
||||
},
|
||||
deleteTaskListItem() {
|
||||
eventHub.$emit('delete-task-list-item', this.$el.closest('li').dataset.sourcepos);
|
||||
this.closeDropdown();
|
||||
},
|
||||
closeDropdown() {
|
||||
this.$refs.dropdown.close();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<gl-dropdown
|
||||
<gl-disclosure-dropdown
|
||||
v-if="canUpdate"
|
||||
ref="dropdown"
|
||||
class="task-list-item-actions-wrapper"
|
||||
category="tertiary"
|
||||
icon="ellipsis_v"
|
||||
lazy
|
||||
no-caret
|
||||
right
|
||||
:text="$options.i18n.taskActions"
|
||||
placement="right"
|
||||
:toggle-text="$options.i18n.taskActions"
|
||||
text-sr-only
|
||||
toggle-class="task-list-item-actions gl-opacity-0 gl-p-2!"
|
||||
toggle-class="task-list-item-actions gl-opacity-0 gl-p-2! "
|
||||
>
|
||||
<gl-dropdown-item v-if="canUpdate" @click="convertToTask">
|
||||
{{ $options.i18n.convertToTask }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="canUpdate" variant="danger" @click="deleteTaskListItem">
|
||||
{{ $options.i18n.delete }}
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
<gl-disclosure-dropdown-item class="gl-ml-2!" @action="convertToTask">
|
||||
<template #list-item>
|
||||
{{ $options.i18n.convertToTask }}
|
||||
</template>
|
||||
</gl-disclosure-dropdown-item>
|
||||
<gl-disclosure-dropdown-item class="gl-ml-2!" @action="deleteTaskListItem">
|
||||
<template #list-item>
|
||||
<span class="gl-text-red-500!">{{ $options.i18n.delete }}</span>
|
||||
</template>
|
||||
</gl-disclosure-dropdown-item>
|
||||
</gl-disclosure-dropdown>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { NAME_SORT_FIELD } from './common';
|
|||
// Translations strings
|
||||
|
||||
export const CONTAINER_REGISTRY_TITLE = s__('ContainerRegistry|Container Registry');
|
||||
export const SETTINGS_TEXT = s__('ContainerRegistry|Configure in settings');
|
||||
export const CONNECTION_ERROR_TITLE = s__('ContainerRegistry|Docker connection error');
|
||||
export const CONNECTION_ERROR_MESSAGE = s__(
|
||||
`ContainerRegistry|We are having trouble connecting to the Container Registry. Please try refreshing the page. If this error persists, please review %{docLinkStart}the troubleshooting documentation%{docLinkEnd}.`,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ export default () => {
|
|||
isGroupPage,
|
||||
isAdmin,
|
||||
showCleanupPolicyLink,
|
||||
showContainerRegistrySettings,
|
||||
showUnfinishedTagCleanupCallout,
|
||||
connectionError,
|
||||
invalidPathError,
|
||||
|
|
@ -69,6 +70,7 @@ export default () => {
|
|||
isGroupPage: parseBoolean(isGroupPage),
|
||||
isAdmin: parseBoolean(isAdmin),
|
||||
showCleanupPolicyLink: parseBoolean(showCleanupPolicyLink),
|
||||
showContainerRegistrySettings: parseBoolean(showContainerRegistrySettings),
|
||||
showUnfinishedTagCleanupCallout: parseBoolean(showUnfinishedTagCleanupCallout),
|
||||
connectionError: parseBoolean(connectionError),
|
||||
invalidPathError: parseBoolean(invalidPathError),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import {
|
||||
GlButton,
|
||||
GlEmptyState,
|
||||
GlTooltipDirective,
|
||||
GlSprintf,
|
||||
|
|
@ -28,12 +29,14 @@ import {
|
|||
GRAPHQL_PAGE_SIZE,
|
||||
FETCH_IMAGES_LIST_ERROR_MESSAGE,
|
||||
SORT_FIELDS,
|
||||
SETTINGS_TEXT,
|
||||
} from '../constants/index';
|
||||
import getContainerRepositoriesDetails from '../graphql/queries/get_container_repositories_details.query.graphql';
|
||||
|
||||
export default {
|
||||
name: 'RegistryListPage',
|
||||
components: {
|
||||
GlButton,
|
||||
GlEmptyState,
|
||||
ProjectEmptyState: () =>
|
||||
import(
|
||||
|
|
@ -75,6 +78,7 @@ export default {
|
|||
CONNECTION_ERROR_MESSAGE,
|
||||
EMPTY_RESULT_TITLE,
|
||||
EMPTY_RESULT_MESSAGE,
|
||||
SETTINGS_TEXT,
|
||||
},
|
||||
searchConfig: SORT_FIELDS,
|
||||
apollo: {
|
||||
|
|
@ -306,6 +310,13 @@ export default {
|
|||
:docker-push-command="dockerPushCommand"
|
||||
:docker-login-command="dockerLoginCommand"
|
||||
/>
|
||||
<gl-button
|
||||
v-if="config.showContainerRegistrySettings"
|
||||
v-gl-tooltip="$options.i18n.SETTINGS_TEXT"
|
||||
icon="settings"
|
||||
:href="config.cleanupPoliciesSettingsPath"
|
||||
:aria-label="$options.i18n.SETTINGS_TEXT"
|
||||
/>
|
||||
</template>
|
||||
</registry-header>
|
||||
<persisted-search
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isUserAvatarListExpanded: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
approvers() {
|
||||
return this.approvalState.approvedBy?.nodes || [];
|
||||
|
|
@ -120,6 +125,14 @@ export default {
|
|||
return gon.current_user_id;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onUserAvatarListExpanded() {
|
||||
this.isUserAvatarListExpanded = true;
|
||||
},
|
||||
onUserAvatarListCollapsed() {
|
||||
this.isUserAvatarListExpanded = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -130,9 +143,12 @@ export default {
|
|||
<span v-if="approvalLeftMessage">{{ message }}</span>
|
||||
<span v-else class="gl-font-weight-bold">{{ message }}</span>
|
||||
<user-avatar-list
|
||||
class="gl-display-inline-flex gl-vertical-align-middle"
|
||||
class="gl-display-inline-block"
|
||||
:class="{ 'gl-pt-1': isUserAvatarListExpanded }"
|
||||
:img-size="24"
|
||||
:items="approvers"
|
||||
@expanded="onUserAvatarListExpanded"
|
||||
@collapsed="onUserAvatarListCollapsed"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="disableCommittersApproval && currentUserHasCommitted">
|
||||
|
|
|
|||
|
|
@ -60,9 +60,11 @@ export default {
|
|||
methods: {
|
||||
expand() {
|
||||
this.isExpanded = true;
|
||||
this.$emit('expanded');
|
||||
},
|
||||
collapse() {
|
||||
this.isExpanded = false;
|
||||
this.$emit('collapsed');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ class DashboardController < Dashboard::ApplicationController
|
|||
before_action :set_show_full_reference, only: [:issues, :merge_requests]
|
||||
before_action :check_filters_presence!, only: [:issues, :merge_requests]
|
||||
|
||||
before_action only: :merge_requests do
|
||||
push_frontend_feature_flag(:mr_approved_filter, type: :ops)
|
||||
end
|
||||
|
||||
respond_to :html
|
||||
|
||||
feature_category :user_profile, [:activity]
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ class GroupsController < Groups::ApplicationController
|
|||
push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?)
|
||||
end
|
||||
|
||||
before_action only: :merge_requests do
|
||||
push_frontend_feature_flag(:mr_approved_filter, type: :ops)
|
||||
end
|
||||
|
||||
helper_method :captcha_required?
|
||||
|
||||
skip_cross_project_access_check :index, :new, :create, :edit, :update, :destroy, :projects
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
before_action :authenticate_user!, only: [:assign_related_issues]
|
||||
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
|
||||
|
||||
before_action only: :index do
|
||||
push_frontend_feature_flag(:mr_approved_filter, type: :ops)
|
||||
end
|
||||
|
||||
before_action only: [:show, :diffs] do
|
||||
push_frontend_feature_flag(:content_editor_on_issues, project&.group)
|
||||
push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?)
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class MergeRequestsFinder < IssuableFinder
|
|||
|
||||
def by_approved(items)
|
||||
approved_param = Gitlab::Utils.to_boolean(params.fetch(:approved, nil))
|
||||
return items if approved_param.nil?
|
||||
return items if approved_param.nil? || Feature.disabled?(:mr_approved_filter, type: :ops)
|
||||
|
||||
if approved_param
|
||||
items.with_approvals
|
||||
|
|
|
|||
|
|
@ -57,7 +57,10 @@ module Resolvers
|
|||
|
||||
argument :approved, GraphQL::Types::Boolean,
|
||||
required: false,
|
||||
description: 'Limit results to approved merge requests.'
|
||||
description: <<~DESC
|
||||
Limit results to approved merge requests.
|
||||
Available only when the feature flag `mr_approved_filter` is enabled.
|
||||
DESC
|
||||
|
||||
argument :created_after, Types::TimeType,
|
||||
required: false,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
.row.justify-content-center
|
||||
.col-md-5.new-session-forms-container
|
||||
.login-page
|
||||
#signin-container{ class: "#{'borderless' if Feature.enabled?(:restyle_login_page, @project)}" }
|
||||
#signin-container{ class: ('borderless' if Feature.enabled?(:restyle_login_page, @project)) }
|
||||
- if any_form_based_providers_enabled?
|
||||
= render 'devise/shared/tabs_ldap', show_password_form: allow_admin_mode_password_authentication_for_web?, render_signup_link: false
|
||||
- else
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
.row.justify-content-center
|
||||
.col-md-5.new-session-forms-container
|
||||
.login-page
|
||||
#signin-container
|
||||
#signin-container{ class: ('borderless' if Feature.enabled?(:restyle_login_page, @project)) }
|
||||
= render 'devise/shared/tab_single', tab_title: _('Enter Admin Mode')
|
||||
.tab-content
|
||||
.login-box.tab-pane.gl-p-5.active{ id: 'login-pane', role: 'tabpanel' }
|
||||
|
|
|
|||
|
|
@ -6,15 +6,29 @@
|
|||
- notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil
|
||||
|
||||
.nav-controls.issues-nav-controls.gl-font-size-0
|
||||
- if show_feed_buttons
|
||||
= render 'shared/issuable/feed_buttons'
|
||||
|
||||
.js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, container_class: 'gl-mr-3', can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) } }
|
||||
|
||||
- if @can_bulk_update
|
||||
= button_tag _("Edit issues"), class: "gl-button btn btn-default gl-mr-3 js-bulk-update-toggle"
|
||||
- if show_new_issue_link?(@project)
|
||||
= link_to _("New issue"), new_project_issue_path(@project,
|
||||
issue: { milestone_id: finder.milestones.first.try(:id) }),
|
||||
class: "gl-button btn btn-confirm",
|
||||
class: "gl-button btn btn-confirm gl-mr-3",
|
||||
id: "new_issue_link"
|
||||
|
||||
.dropdown.gl-dropdown
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { toggle: 'dropdown', title: _('Actions') } do
|
||||
= sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon"
|
||||
%span.gl-sr-only
|
||||
= _('Actions')
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do
|
||||
%span.gl-dropdown-button-text= _('Actions')
|
||||
= sprite_icon "chevron-down", size: 16, css_class: "dropdown-icon gl-icon"
|
||||
.dropdown-menu.dropdown-menu-right
|
||||
.gl-dropdown-inner
|
||||
.gl-dropdown-contents
|
||||
%ul
|
||||
.js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) } }
|
||||
%li.gl-dropdown-divider
|
||||
%hr.dropdown-divider
|
||||
%li.gl-dropdown-item
|
||||
- if show_feed_buttons
|
||||
= render 'shared/issuable/feed_buttons'
|
||||
|
|
|
|||
|
|
@ -1,12 +1,27 @@
|
|||
- issuable_type = 'merge_request'
|
||||
- notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil
|
||||
|
||||
= render 'shared/issuable/feed_buttons', show_calendar_button: false
|
||||
.js-csv-import-export-buttons{ data: { show_export_button: "true", issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_merge_requests_path(@project, request.query_parameters), container_class: 'gl-mr-3' } }
|
||||
|
||||
- if @can_bulk_update
|
||||
= render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-mr-3 js-bulk-update-toggle' }) do
|
||||
= _("Edit merge requests")
|
||||
- if merge_project
|
||||
= render Pajamas::ButtonComponent.new(href: new_merge_request_path, variant: :confirm) do
|
||||
= _("New merge request")
|
||||
|
||||
.dropdown.gl-dropdown
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { toggle: 'dropdown', title: _('Actions') } do
|
||||
= sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon"
|
||||
%span.gl-sr-only
|
||||
= _('Actions')
|
||||
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do
|
||||
%span.gl-dropdown-button-text= _('Actions')
|
||||
= sprite_icon "chevron-down", size: 16, css_class: "dropdown-icon gl-icon"
|
||||
.dropdown-menu.dropdown-menu-right
|
||||
.gl-dropdown-inner
|
||||
.gl-dropdown-contents
|
||||
%ul
|
||||
.js-csv-import-export-buttons{ data: { show_export_button: "true", issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_merge_requests_path(@project, request.query_parameters) } }
|
||||
%li.gl-dropdown-divider
|
||||
%hr.dropdown-divider
|
||||
%li.gl-dropdown-item
|
||||
= render 'shared/issuable/feed_buttons', show_calendar_button: false
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"gid_prefix": container_repository_gid_prefix,
|
||||
"is_admin": current_user&.admin.to_s,
|
||||
"show_cleanup_policy_link": show_cleanup_policy_link(@project).to_s,
|
||||
"show_container_registry_settings": show_container_registry_settings(@project).to_s,
|
||||
"cleanup_policies_settings_path": project_settings_packages_and_registries_path(@project),
|
||||
connection_error: (!!@connection_error).to_s,
|
||||
invalid_path_error: (!!@invalid_path_error).to_s,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
= link_to _('New issue'), button_path, class: 'gl-button btn btn-confirm', id: 'new_issue_link'
|
||||
|
||||
- if show_import_button
|
||||
.js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: 'issue', import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-w-full gl-sm-w-auto gl-sm-mr-3 gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } }
|
||||
.js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: 'issue', import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) } }
|
||||
%hr
|
||||
%p.gl-text-center.gl-mb-0
|
||||
%strong
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
- show_calendar_button = local_assigns.fetch(:show_calendar_button, true)
|
||||
|
||||
= render Pajamas::ButtonComponent.new(href: safe_params.merge(rss_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to RSS feed'), 'aria-label': _('Subscribe to RSS feed'), data: { container: 'body', testid: 'rss-feed-link' } }) do
|
||||
= sprite_icon('rss')
|
||||
|
||||
- if show_calendar_button
|
||||
= render Pajamas::ButtonComponent.new(href: safe_params.merge(calendar_url_options), button_options: { class: 'has-tooltip btn-icon', title: _('Subscribe to calendar'), 'aria-label': _('Subscribe to calendar'), data: { container: 'body' } }) do
|
||||
= sprite_icon('calendar')
|
||||
= link_to safe_params.merge(calendar_url_options), class: 'dropdown-item' do
|
||||
.gl-dropdown-item-text-wrapper
|
||||
= _("Subscribe to calendar")
|
||||
|
||||
= link_to safe_params.merge(rss_url_options), class: 'dropdown-item' do
|
||||
.gl-dropdown-item-text-wrapper
|
||||
= _("Subscribe to RSS feed")
|
||||
|
|
|
|||
|
|
@ -162,14 +162,15 @@
|
|||
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
|
||||
%button.gl-button.btn.btn-link{ type: 'button' }
|
||||
= _('No')
|
||||
#js-dropdown-approved.filtered-search-input-dropdown-menu.dropdown-menu
|
||||
%ul.filter-dropdown{ data: { dropdown: true } }
|
||||
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
|
||||
%button.gl-button.btn.btn-link{ type: 'button' }
|
||||
= _('Yes')
|
||||
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
|
||||
%button.gl-button.btn.btn-link{ type: 'button' }
|
||||
= _('No')
|
||||
- if ::Feature.enabled?(:mr_approved_filter, type: :ops)
|
||||
#js-dropdown-approved.filtered-search-input-dropdown-menu.dropdown-menu
|
||||
%ul.filter-dropdown{ data: { dropdown: true } }
|
||||
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
|
||||
%button.gl-button.btn.btn-link{ type: 'button' }
|
||||
= _('Yes')
|
||||
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
|
||||
%button.gl-button.btn.btn-link{ type: 'button' }
|
||||
= _('No')
|
||||
#js-dropdown-confidential.filtered-search-input-dropdown-menu.dropdown-menu
|
||||
%ul.filter-dropdown{ data: { dropdown: true } }
|
||||
%li.filter-dropdown-item{ data: { value: 'yes', capitalize: true } }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: refactor_security_extension
|
||||
introduced_by_url:
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84896
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365320
|
||||
milestone: '14.10'
|
||||
type: development
|
||||
group: group::threat insights
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: mr_approved_filter
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118087
|
||||
rollout_issue_url:
|
||||
milestone: '16.0'
|
||||
type: ops
|
||||
group: group::code review
|
||||
default_enabled: false
|
||||
|
|
@ -15240,7 +15240,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="groupmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="groupmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="groupmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="groupmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="groupmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -16572,7 +16572,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestassigneeassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestassigneeassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestassigneeassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestassigneeassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestassigneeassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -16607,7 +16607,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestassigneeauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestassigneeauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestassigneeauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestassigneeauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestassigneeauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -16659,7 +16659,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestassigneereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestassigneereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestassigneereviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestassigneereviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestassigneereviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -16822,7 +16822,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestauthorassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestauthorassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestauthorassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestauthorassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestauthorassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -16857,7 +16857,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestauthorauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestauthorauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestauthorauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestauthorauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestauthorauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -16909,7 +16909,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestauthorreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestauthorreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestauthorreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestauthorreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestauthorreviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -17091,7 +17091,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestparticipantassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestparticipantassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestparticipantassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestparticipantassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestparticipantassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -17126,7 +17126,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestparticipantauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestparticipantauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestparticipantauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestparticipantauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestparticipantauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -17178,7 +17178,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestparticipantreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestparticipantreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestparticipantreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestparticipantreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestparticipantreviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -17360,7 +17360,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestreviewerassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestreviewerassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestreviewerassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestreviewerassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestreviewerassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -17395,7 +17395,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestreviewerauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestreviewerauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestreviewerauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestreviewerauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="mergerequestreviewerauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -17447,7 +17447,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mergerequestreviewerreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="mergerequestreviewerreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="mergerequestreviewerreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="mergerequestreviewerreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="mergerequestreviewerreviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -19445,7 +19445,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="projectmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="projectmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="projectmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="projectmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="projectmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -21757,7 +21757,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="usercoreassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="usercoreassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="usercoreassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="usercoreassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="usercoreassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -21792,7 +21792,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="usercoreauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="usercoreauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="usercoreauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="usercoreauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="usercoreauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -21844,7 +21844,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="usercorereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="usercorereviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="usercorereviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="usercorereviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="usercorereviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
@ -26440,7 +26440,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="userassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="userassignedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="userassignedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="userassignedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="userassignedmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -26475,7 +26475,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="userauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="userauthoredmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="userauthoredmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="userauthoredmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
| <a id="userauthoredmergerequestscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Merge requests created before this timestamp. |
|
||||
|
|
@ -26527,7 +26527,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="userreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. |
|
||||
| <a id="userreviewrequestedmergerequestsapproved"></a>`approved` | [`Boolean`](#boolean) | Limit results to approved merge requests. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| <a id="userreviewrequestedmergerequestsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of the assignee. |
|
||||
| <a id="userreviewrequestedmergerequestsauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author. |
|
||||
| <a id="userreviewrequestedmergerequestscreatedafter"></a>`createdAfter` | [`Time`](#time) | Merge requests created after this timestamp. |
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Supported attributes:
|
|||
| ------------------------------- | -------------- | -------- | ----------- |
|
||||
| `approved_by_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have been approved by all the users with the given `id`. Maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
|
||||
| `approver_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| `assignee_id` | integer | **{dotted-circle}** No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
|
||||
| `author_id` | integer | **{dotted-circle}** No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
|
||||
| `author_username` | string | **{dotted-circle}** No | Returns merge requests created by the given `username`. Mutually exclusive with `author_id`. |
|
||||
|
|
@ -250,7 +250,7 @@ Supported attributes:
|
|||
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||
| `approved_by_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
|
||||
| `approver_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have specified all the users with the given `id` as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| `assignee_id` | integer | **{dotted-circle}** No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
|
||||
| `author_id` | integer | **{dotted-circle}** No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. |
|
||||
| `author_username` | string | **{dotted-circle}** No | Returns merge requests created by the given `username`. Mutually exclusive with `author_id`. |
|
||||
|
|
@ -441,7 +441,7 @@ Supported attributes:
|
|||
| `approved_by_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have been approved by all the users with the given `id`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
|
||||
| `approved_by_usernames` **(PREMIUM)** | string array | **{dotted-circle}** No | Returns merge requests which have been approved by all the users with the given `username`, with a maximum of 5. `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
|
||||
| `approver_ids` **(PREMIUM)** | integer array | **{dotted-circle}** No | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. |
|
||||
| `approved` | string | **{dotted-circle}** No | Filters merge requests by their `approved` status. `yes` returns only approved merge requests. `no` returns only non-approved merge requests. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3159) in GitLab 15.11. Available only when the feature flag `mr_approved_filter` is enabled. |
|
||||
| `assignee_id` | integer | **{dotted-circle}** No | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
|
||||
| `author_id` | integer | **{dotted-circle}** No | Returns merge requests created by the given user `id`. Mutually exclusive with `author_username`. |
|
||||
| `author_username` | string | **{dotted-circle}** No | Returns merge requests created by the given `username`. Mutually exclusive with `author_id`. |
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ self-managed GitLab instances with Jira Cloud, you can do one of the following:
|
|||
|
||||
[Prerequisites](#prerequisites-1)
|
||||
|
||||
To configure your Atlassian Cloud instance so you can install applications
|
||||
To configure your Jira instance so you can install applications
|
||||
from outside the Marketplace:
|
||||
|
||||
1. Sign in to your Jira instance as an administrator.
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ Importing large projects may take several minutes depending on the size of the i
|
|||
|
||||
To import Jira issues to a GitLab project:
|
||||
|
||||
1. On the **{issues}** **Issues** page, select **Import Issues** (**{import}**) **> Import from Jira**.
|
||||
1. On the **{issues}** **Issues** page, select **Actions** (**{ellipsis_v}**) **> Import from Jira**.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ To import issues:
|
|||
|
||||
1. Go to your project's Issues list page.
|
||||
1. Open the import feature, depending if the project has issues:
|
||||
- The project has existing issues: in the upper-right corner, next to **Edit issues**, select the import icon (**{import}**).
|
||||
- The project has existing issues: in the upper-right corner, next to **Edit issues**, select **Actions** (**{ellipsis_v}**) **> Import CSV**.
|
||||
- The project has no issues: in the middle of the page, select **Import CSV**.
|
||||
1. Select the file you want to import, and then select **Import issues**.
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ server's time zone.
|
|||
|
||||
Issues with due dates can also be exported as an iCalendar feed. The URL of the
|
||||
feed can be added to calendar applications. The feed is accessible by selecting
|
||||
the **Subscribe to calendar** button on the following pages:
|
||||
the **Subscribe to calendar** option in the **Actions** (**{ellipsis_v}**) dropdown
|
||||
list on the following pages:
|
||||
|
||||
- The **Assigned Issues** page linked on the right side of the GitLab header
|
||||
- The **Project Issues** page
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ To export merge requests to a CSV file:
|
|||
1. On the left sidebar, select **Merge requests** .
|
||||
1. Add any searches or filters. This can help you keep the size of the CSV file under the 15 MB limit. The limit ensures
|
||||
the file can be emailed to a variety of email providers.
|
||||
1. Select **Export as CSV** (**{export}**).
|
||||
1. Select **Actions** (**{ellipsis_v}**) **> Export as CSV**.
|
||||
1. Confirm the correct number of merge requests are to be exported.
|
||||
1. Select **Export merge requests**.
|
||||
|
||||
|
|
|
|||
|
|
@ -11478,6 +11478,9 @@ msgstr ""
|
|||
msgid "ContainerRegistry|Configuration digest: %{digest}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Configure in settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContainerRegistry|Container Registry"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -38210,9 +38213,6 @@ msgstr ""
|
|||
msgid "Runners|Clear selection"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Cloud templates"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Command to register runner"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -52109,6 +52109,9 @@ msgstr ""
|
|||
msgid "ciReport|Container Scanning"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Container Scanning detects known vulnerabilities in your container images."
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Container scanning"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -52139,7 +52142,7 @@ msgstr ""
|
|||
msgid "ciReport|Dependency Scanning"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies."
|
||||
msgid "ciReport|Dependency Scanning detects known vulnerabilities in your project's dependencies."
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Dependency scanning"
|
||||
|
|
@ -52166,7 +52169,7 @@ msgstr ""
|
|||
msgid "ciReport|Dynamic Application Security Testing (DAST)"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
|
||||
msgid "ciReport|Dynamic Application Security Testing (DAST) detects vulnerabilities in your web application."
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Failed to load %{reportName} report"
|
||||
|
|
@ -52261,7 +52264,7 @@ msgstr ""
|
|||
msgid "ciReport|Secret Detection"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Secret Detection detects secrets and credentials vulnerabilities in your source code."
|
||||
msgid "ciReport|Secret Detection detects leaked credentials in your source code."
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Secret detection"
|
||||
|
|
@ -52294,7 +52297,7 @@ msgstr ""
|
|||
msgid "ciReport|Static Application Security Testing (SAST)"
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
|
||||
msgid "ciReport|Static Application Security Testing (SAST) detects potential vulnerabilities in your source code."
|
||||
msgstr ""
|
||||
|
||||
msgid "ciReport|TTFB P90"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@ module QA
|
|||
view 'app/assets/javascripts/issuable/components/csv_import_export_buttons.vue' do
|
||||
element :export_as_csv_button
|
||||
element :import_from_jira_link
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/issues/list/components/issues_list_app.vue' do
|
||||
element :issues_list_more_actions_dropdown
|
||||
end
|
||||
|
||||
view 'app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue' do
|
||||
element :import_issues_dropdown
|
||||
end
|
||||
|
||||
|
|
@ -59,6 +66,10 @@ module QA
|
|||
click_element(:import_issues_dropdown)
|
||||
end
|
||||
|
||||
def click_issues_list_more_actions_dropdown
|
||||
click_element(:issues_list_more_actions_dropdown)
|
||||
end
|
||||
|
||||
def export_issues_modal
|
||||
find_element(:export_issuable_modal)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Manage', product_group: :import,
|
||||
RSpec.describe 'Manage', product_group: :import_and_integrate,
|
||||
quarantine: {
|
||||
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/407297',
|
||||
type: :investigating
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ require "etc"
|
|||
# rubocop:disable Rails/Pluck
|
||||
module QA
|
||||
RSpec.describe 'Manage', :github, requires_admin: 'creates users', only: { job: 'large-github-import' } do
|
||||
describe 'Project import', product_group: :import do # rubocop:disable RSpec/MultipleMemoizedHelpers
|
||||
describe 'Project import', product_group: :import_and_integrate do # rubocop:disable RSpec/MultipleMemoizedHelpers
|
||||
let(:github_repo) { ENV['QA_LARGE_IMPORT_REPO'] || 'rspec/rspec-core' }
|
||||
let(:import_max_duration) { ENV['QA_LARGE_IMPORT_DURATION']&.to_i || 7200 }
|
||||
let(:logger) { Runtime::Logger.logger }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module QA
|
|||
:requires_admin,
|
||||
:integrations,
|
||||
:orchestrated,
|
||||
product_group: :integrations
|
||||
product_group: :import_and_integrate
|
||||
) do
|
||||
before(:context) do
|
||||
toggle_local_requests(true)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe "Manage", :reliable, product_group: :import do
|
||||
RSpec.describe "Manage", :reliable, product_group: :import_and_integrate do
|
||||
include_context "with gitlab group migration"
|
||||
|
||||
describe "Gitlab migration" do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
let!(:source_issue) do
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# rubocop:disable Rails/Pluck, Layout/LineLength, RSpec/MultipleMemoizedHelpers
|
||||
module QA
|
||||
RSpec.describe "Manage", :skip_live_env, only: { job: "large-gitlab-import" } do
|
||||
describe "Gitlab migration", orchestrated: false, product_group: :import do
|
||||
describe "Gitlab migration", orchestrated: false, product_group: :import_and_integrate do
|
||||
include_context "with gitlab group migration"
|
||||
|
||||
let!(:logger) { Runtime::Logger.logger }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
let!(:source_member) do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
let!(:source_project_with_readme) { true }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
context 'with ci pipeline' do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
# this spec is used as a sanity test for gitlab migration because it can run outside of orchestrated setup
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage' do
|
||||
describe 'Gitlab migration', product_group: :import do
|
||||
describe 'Gitlab migration', product_group: :import_and_integrate do
|
||||
include_context 'with gitlab project migration'
|
||||
|
||||
context 'with release' do
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do
|
||||
describe 'rate limits', :reliable, product_group: :integrations do
|
||||
describe 'rate limits', :reliable, product_group: :import_and_integrate do
|
||||
let(:rate_limited_user) { Resource::User.fabricate_via_api! }
|
||||
let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) }
|
||||
let!(:request) { Runtime::API::Request.new(api_client, '/users') }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
RSpec.describe 'Manage', product_group: :import do
|
||||
RSpec.describe 'Manage', product_group: :import_and_integrate do
|
||||
describe 'GitHub import' do
|
||||
include_context 'with github import'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do
|
||||
describe 'Jenkins integration', product_group: :integrations do
|
||||
describe 'Jenkins integration', product_group: :import_and_integrate do
|
||||
let(:jenkins_server) { Service::DockerRun::Jenkins.new }
|
||||
|
||||
let(:jenkins_client) do
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module QA
|
|||
RSpec.describe 'Manage' do
|
||||
include Support::API
|
||||
|
||||
describe 'Jira integration', :jira, :orchestrated, :requires_admin, product_group: :integrations do
|
||||
describe 'Jira integration', :jira, :orchestrated, :requires_admin, product_group: :import_and_integrate do
|
||||
let(:jira_project_key) { 'JITP' }
|
||||
let(:project) do
|
||||
Resource::Project.fabricate_via_api! do |project|
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module QA
|
||||
RSpec.describe 'Manage', :reliable do
|
||||
describe 'Jira issue import', :jira, :orchestrated, :requires_admin, product_group: :integrations do
|
||||
describe 'Jira issue import', :jira, :orchestrated, :requires_admin, product_group: :import_and_integrate do
|
||||
let(:jira_project_key) { "JITD" }
|
||||
let(:jira_issue_title) { "[#{jira_project_key}-1] Jira to GitLab Test Issue" }
|
||||
let(:jira_issue_description) { "This issue is for testing importing Jira issues to GitLab." }
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
RSpec.describe 'Manage', :orchestrated, :runner, :requires_admin, :smtp, product_group: :integrations do
|
||||
RSpec.describe 'Manage', :orchestrated, :runner, :requires_admin, :smtp, product_group: :import_and_integrate do
|
||||
describe 'Pipeline status emails' do
|
||||
let(:executor) { "qa-runner-#{Time.now.to_i}" }
|
||||
let(:emails) { %w[foo@bar.com baz@buzz.com] }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module QA
|
||||
describe 'Manage', :reliable, product_group: :import do
|
||||
describe 'Manage', :reliable, product_group: :import_and_integrate do
|
||||
describe 'Gitlab migration' do
|
||||
include_context "with gitlab group migration"
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ module QA
|
|||
|
||||
it 'successfully exports issues list as CSV', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347968' do
|
||||
Page::Project::Issue::Index.perform do |index|
|
||||
index.click_issues_list_more_actions_dropdown
|
||||
|
||||
index.click_export_as_csv_button
|
||||
|
||||
expect(index.export_issues_modal).to have_content('2 issues selected')
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ postgresql:
|
|||
memory: 1000Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1600Mi
|
||||
memory: 1800Mi
|
||||
master:
|
||||
nodeSelector:
|
||||
preemptible: "false"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ RSpec.describe 'Group issues page', feature_category: :subgroups do
|
|||
context 'rss feed' do
|
||||
let(:access_level) { ProjectFeature::ENABLED }
|
||||
|
||||
before do
|
||||
click_button 'Actions'
|
||||
end
|
||||
|
||||
context 'when signed in' do
|
||||
let(:user) do
|
||||
user_in_group.ensure_feed_token
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ RSpec.describe 'Issues csv', :js, feature_category: :team_planning do
|
|||
|
||||
def request_csv(params = {})
|
||||
visit project_issues_path(project, params)
|
||||
click_button 'Actions'
|
||||
click_button 'Export as CSV'
|
||||
click_on 'Export issues'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ RSpec.describe 'Project Issues RSS', :js, feature_category: :team_planning do
|
|||
before do
|
||||
sign_in(user)
|
||||
visit path
|
||||
click_button 'Actions'
|
||||
end
|
||||
|
||||
it_behaves_like "it has an RSS link with current_user's feed token"
|
||||
|
|
@ -32,6 +33,7 @@ RSpec.describe 'Project Issues RSS', :js, feature_category: :team_planning do
|
|||
context 'when signed out' do
|
||||
before do
|
||||
visit path
|
||||
click_button 'Actions'
|
||||
end
|
||||
|
||||
it_behaves_like "it has an RSS link without a feed token"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ RSpec.describe 'Project Merge Requests RSS', feature_category: :code_review_work
|
|||
visit path
|
||||
end
|
||||
|
||||
it_behaves_like "it has an RSS button with current_user's feed token"
|
||||
it_behaves_like "it has an RSS link with current_user's feed token"
|
||||
it_behaves_like "an autodiscoverable RSS feed with current_user's feed token"
|
||||
end
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ RSpec.describe 'Project Merge Requests RSS', feature_category: :code_review_work
|
|||
visit path
|
||||
end
|
||||
|
||||
it_behaves_like "it has an RSS button without a feed token"
|
||||
it_behaves_like "it has an RSS link without a feed token"
|
||||
it_behaves_like "an autodiscoverable RSS feed without a feed token"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ RSpec.describe 'Merge Requests > Exports as CSV', :js, feature_category: :code_r
|
|||
|
||||
context 'button is clicked' do
|
||||
before do
|
||||
click_button 'Actions'
|
||||
click_button 'Export as CSV'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,20 @@ RSpec.describe 'Container Registry', :js, feature_category: :projects do
|
|||
expect(page).to have_title _('Container Registry')
|
||||
end
|
||||
|
||||
it 'does not have link to settings' do
|
||||
visit_container_registry
|
||||
|
||||
expect(page).not_to have_link _('Configure in settings')
|
||||
end
|
||||
|
||||
it 'has link to settings when user is maintainer' do
|
||||
project.add_maintainer(user)
|
||||
|
||||
visit_container_registry
|
||||
|
||||
expect(page).to have_link _('Configure in settings')
|
||||
end
|
||||
|
||||
context 'when there are no image repositories' do
|
||||
it 'list page has no container title' do
|
||||
visit_container_registry
|
||||
|
|
|
|||
|
|
@ -498,16 +498,40 @@ RSpec.describe MergeRequestsFinder, feature_category: :code_review_workflow do
|
|||
create(:approval, merge_request: merge_request3, user: user2)
|
||||
end
|
||||
|
||||
it 'for approved' do
|
||||
merge_requests = described_class.new(user, { approved: true }).execute
|
||||
context 'when flag `mr_approved_filter` is disabled' do
|
||||
before do
|
||||
stub_feature_flags(mr_approved_filter: false)
|
||||
end
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request3)
|
||||
it 'for approved' do
|
||||
merge_requests = described_class.new(user, { approved: true }).execute
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request4, merge_request5)
|
||||
end
|
||||
|
||||
it 'for not approved' do
|
||||
merge_requests = described_class.new(user, { approved: false }).execute
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request4, merge_request5)
|
||||
end
|
||||
end
|
||||
|
||||
it 'for not approved' do
|
||||
merge_requests = described_class.new(user, { approved: false }).execute
|
||||
context 'when flag `mr_approved_filter` is enabled' do
|
||||
before do
|
||||
stub_feature_flags(mr_approved_filter: true)
|
||||
end
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request4, merge_request5)
|
||||
it 'for approved' do
|
||||
merge_requests = described_class.new(user, { approved: true }).execute
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request3)
|
||||
end
|
||||
|
||||
it 'for not approved' do
|
||||
merge_requests = described_class.new(user, { approved: false }).execute
|
||||
|
||||
expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request4, merge_request5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,19 +6,12 @@ import {
|
|||
LINUX_PLATFORM,
|
||||
MACOS_PLATFORM,
|
||||
WINDOWS_PLATFORM,
|
||||
AWS_PLATFORM,
|
||||
DOCKER_HELP_URL,
|
||||
KUBERNETES_HELP_URL,
|
||||
} from '~/ci/runner/constants';
|
||||
|
||||
import RunnerPlatformsRadioGroup from '~/ci/runner/components/runner_platforms_radio_group.vue';
|
||||
|
||||
const mockProvide = {
|
||||
awsImgPath: 'awsLogo.svg',
|
||||
dockerImgPath: 'dockerLogo.svg',
|
||||
kubernetesImgPath: 'kubernetesLogo.svg',
|
||||
};
|
||||
|
||||
describe('RunnerPlatformsRadioGroup', () => {
|
||||
let wrapper;
|
||||
|
||||
|
|
@ -35,7 +28,6 @@ describe('RunnerPlatformsRadioGroup', () => {
|
|||
value: null,
|
||||
...props,
|
||||
},
|
||||
provide: mockProvide,
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
|
@ -51,7 +43,6 @@ describe('RunnerPlatformsRadioGroup', () => {
|
|||
['Linux', null],
|
||||
['macOS', null],
|
||||
['Windows', null],
|
||||
['AWS', expect.any(String)],
|
||||
['Docker', expect.any(String)],
|
||||
['Kubernetes', expect.any(String)],
|
||||
]);
|
||||
|
|
@ -69,7 +60,6 @@ describe('RunnerPlatformsRadioGroup', () => {
|
|||
${'Linux'} | ${LINUX_PLATFORM}
|
||||
${'macOS'} | ${MACOS_PLATFORM}
|
||||
${'Windows'} | ${WINDOWS_PLATFORM}
|
||||
${'AWS'} | ${AWS_PLATFORM}
|
||||
`('user can select "$text"', async ({ text, value }) => {
|
||||
const radio = findFormRadioByText(text);
|
||||
expect(radio.props('value')).toBe(value);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { GlButton, GlDropdown } from '@gitlab/ui';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import { createMockDirective } from 'helpers/vue_mock_directive';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import CsvExportModal from '~/issuable/components/csv_export_modal.vue';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
|
|
@ -33,8 +32,7 @@ describe('CsvImportExportButtons', () => {
|
|||
});
|
||||
}
|
||||
|
||||
const findExportCsvButton = () => wrapper.findComponent(GlButton);
|
||||
const findImportDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findExportCsvButton = () => wrapper.findByRole('menuitem', { name: 'Export as CSV' });
|
||||
const findImportCsvButton = () => wrapper.findByRole('menuitem', { name: 'Import CSV' });
|
||||
const findImportFromJiraLink = () => wrapper.findByRole('menuitem', { name: 'Import from Jira' });
|
||||
const findExportCsvModal = () => wrapper.findComponent(CsvExportModal);
|
||||
|
|
@ -50,13 +48,6 @@ describe('CsvImportExportButtons', () => {
|
|||
expect(findExportCsvButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('export button has a tooltip', () => {
|
||||
const tooltip = getBinding(findExportCsvButton().element, 'gl-tooltip');
|
||||
|
||||
expect(tooltip).toBeDefined();
|
||||
expect(tooltip.value).toBe('Export as CSV');
|
||||
});
|
||||
|
||||
it('renders the export modal', () => {
|
||||
expect(findExportCsvModal().props()).toMatchObject({ exportCsvPath, issuableCount });
|
||||
});
|
||||
|
|
@ -64,7 +55,7 @@ describe('CsvImportExportButtons', () => {
|
|||
it('opens the export modal', () => {
|
||||
findExportCsvButton().trigger('click');
|
||||
|
||||
expect(glModalDirective).toHaveBeenCalledWith(wrapper.vm.exportModalId);
|
||||
expect(glModalDirective).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -83,79 +74,38 @@ describe('CsvImportExportButtons', () => {
|
|||
});
|
||||
|
||||
describe('when the showImportButton=true', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({ showImportButton: true });
|
||||
});
|
||||
|
||||
it('displays the import dropdown', () => {
|
||||
expect(findImportDropdown().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the import csv menu item', () => {
|
||||
wrapper = createComponent({ showImportButton: true });
|
||||
|
||||
expect(findImportCsvButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
describe('when showLabel=false', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({ showImportButton: true, showLabel: false });
|
||||
});
|
||||
|
||||
it('hides button text', () => {
|
||||
expect(findImportDropdown().props()).toMatchObject({
|
||||
text: 'Import issues',
|
||||
textSrOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('import button has a tooltip', () => {
|
||||
const tooltip = getBinding(findImportDropdown().element, 'gl-tooltip');
|
||||
|
||||
expect(tooltip).toBeDefined();
|
||||
expect(tooltip.value).toBe('Import issues');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when showLabel=true', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({ showImportButton: true, showLabel: true });
|
||||
});
|
||||
|
||||
it('displays a button text', () => {
|
||||
expect(findImportDropdown().props()).toMatchObject({
|
||||
text: 'Import issues',
|
||||
textSrOnly: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('import button has no tooltip', () => {
|
||||
const tooltip = getBinding(findImportDropdown().element, 'gl-tooltip');
|
||||
|
||||
expect(tooltip.value).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the import modal', () => {
|
||||
wrapper = createComponent({ showImportButton: true });
|
||||
|
||||
expect(findImportCsvModal().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('opens the import modal', () => {
|
||||
wrapper = createComponent({ showImportButton: true });
|
||||
|
||||
findImportCsvButton().trigger('click');
|
||||
|
||||
expect(glModalDirective).toHaveBeenCalledWith(wrapper.vm.importModalId);
|
||||
expect(glModalDirective).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('import from jira link', () => {
|
||||
const projectImportJiraPath = 'gitlab-org/gitlab-test/-/import/jira';
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({
|
||||
showImportButton: true,
|
||||
canEdit: true,
|
||||
projectImportJiraPath,
|
||||
});
|
||||
});
|
||||
|
||||
describe('when canEdit=true', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = createComponent({
|
||||
showImportButton: true,
|
||||
canEdit: true,
|
||||
projectImportJiraPath,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the import dropdown item', () => {
|
||||
expect(findImportFromJiraLink().exists()).toBe(true);
|
||||
});
|
||||
|
|
@ -182,8 +132,8 @@ describe('CsvImportExportButtons', () => {
|
|||
wrapper = createComponent({ showImportButton: false });
|
||||
});
|
||||
|
||||
it('does not display the import dropdown', () => {
|
||||
expect(findImportDropdown().exists()).toBe(false);
|
||||
it('does not render the import csv menu item', () => {
|
||||
expect(findImportCsvButton().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not render the import modal', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlEmptyState, GlLink } from '@gitlab/ui';
|
||||
import { GlDropdown, GlEmptyState, GlLink } from '@gitlab/ui';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue';
|
||||
import EmptyStateWithoutAnyIssues from '~/issues/list/components/empty_state_without_any_issues.vue';
|
||||
|
|
@ -26,6 +26,7 @@ describe('EmptyStateWithoutAnyIssues component', () => {
|
|||
};
|
||||
|
||||
const findCsvImportExportButtons = () => wrapper.findComponent(CsvImportExportButtons);
|
||||
const findCsvImportExportDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findGlEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const findGlLink = () => wrapper.findComponent(GlLink);
|
||||
const findIssuesHelpPageLink = () =>
|
||||
|
|
@ -135,6 +136,7 @@ describe('EmptyStateWithoutAnyIssues component', () => {
|
|||
it('renders', () => {
|
||||
mountComponent({ props: { showCsvButtons: true } });
|
||||
|
||||
expect(findCsvImportExportDropdown().props('text')).toBe('Import issues');
|
||||
expect(findCsvImportExportButtons().props()).toMatchObject({
|
||||
exportCsvPath: defaultProps.exportCsvPathWithQuery,
|
||||
issuableCount: 0,
|
||||
|
|
@ -146,6 +148,7 @@ describe('EmptyStateWithoutAnyIssues component', () => {
|
|||
it('does not render', () => {
|
||||
mountComponent({ props: { showCsvButtons: false } });
|
||||
|
||||
expect(findCsvImportExportDropdown().exists()).toBe(false);
|
||||
expect(findCsvImportExportButtons().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlButton } from '@gitlab/ui';
|
||||
import { GlButton, GlDropdown } from '@gitlab/ui';
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { mount, shallowMount } from '@vue/test-utils';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
|
|
@ -11,6 +11,7 @@ import getIssuesCountsQuery from 'ee_else_ce/issues/list/queries/get_issues_coun
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
import { TEST_HOST } from 'helpers/test_constants';
|
||||
import { mountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import {
|
||||
getIssuesCountsQueryResponse,
|
||||
|
|
@ -126,12 +127,16 @@ describe('CE IssuesListApp component', () => {
|
|||
const mockIssuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse);
|
||||
const mockIssuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse);
|
||||
|
||||
const findCalendarButton = () =>
|
||||
wrapper.findByRole('menuitem', { name: IssuesListApp.i18n.calendarLabel });
|
||||
const findCsvImportExportButtons = () => wrapper.findComponent(CsvImportExportButtons);
|
||||
const findDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findIssuableByEmail = () => wrapper.findComponent(IssuableByEmail);
|
||||
const findGlButton = () => wrapper.findComponent(GlButton);
|
||||
const findGlButtons = () => wrapper.findAllComponents(GlButton);
|
||||
const findGlButtonAt = (index) => findGlButtons().at(index);
|
||||
const findIssuableList = () => wrapper.findComponent(IssuableList);
|
||||
const findNewResourceDropdown = () => wrapper.findComponent(NewResourceDropdown);
|
||||
const findRssButton = () => wrapper.findByRole('menuitem', { name: IssuesListApp.i18n.rssLabel });
|
||||
|
||||
const findLabelsToken = () =>
|
||||
findIssuableList()
|
||||
|
|
@ -232,63 +237,66 @@ describe('CE IssuesListApp component', () => {
|
|||
});
|
||||
|
||||
describe('header action buttons', () => {
|
||||
it('renders rss button', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
await waitForPromises();
|
||||
describe('actions dropdown', () => {
|
||||
it('renders', () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
|
||||
expect(findGlButtonAt(0).props('icon')).toBe('rss');
|
||||
expect(findGlButtonAt(0).attributes()).toMatchObject({
|
||||
href: defaultProvide.rssPath,
|
||||
'aria-label': IssuesListApp.i18n.rssLabel,
|
||||
expect(findDropdown().props()).toMatchObject({
|
||||
category: 'tertiary',
|
||||
icon: 'ellipsis_v',
|
||||
text: 'Actions',
|
||||
textSrOnly: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders calendar button', async () => {
|
||||
wrapper = mountComponent({ mountFn: mount });
|
||||
await waitForPromises();
|
||||
describe('csv import/export buttons', () => {
|
||||
describe('when user is signed in', () => {
|
||||
beforeEach(() => {
|
||||
setWindowLocation('?search=refactor&state=opened');
|
||||
|
||||
expect(findGlButtonAt(1).props('icon')).toBe('calendar');
|
||||
expect(findGlButtonAt(1).attributes()).toMatchObject({
|
||||
href: defaultProvide.calendarPath,
|
||||
'aria-label': IssuesListApp.i18n.calendarLabel,
|
||||
});
|
||||
});
|
||||
wrapper = mountComponent({
|
||||
provide: { initialSortBy: CREATED_DESC, isSignedIn: true },
|
||||
mountFn: mount,
|
||||
});
|
||||
|
||||
describe('csv import/export component', () => {
|
||||
describe('when user is signed in', () => {
|
||||
beforeEach(() => {
|
||||
setWindowLocation('?search=refactor&state=opened');
|
||||
|
||||
wrapper = mountComponent({
|
||||
provide: { initialSortBy: CREATED_DESC, isSignedIn: true },
|
||||
mountFn: mount,
|
||||
return waitForPromises();
|
||||
});
|
||||
|
||||
return waitForPromises();
|
||||
it('renders', () => {
|
||||
expect(findCsvImportExportButtons().props()).toMatchObject({
|
||||
exportCsvPath: `${defaultProvide.exportCsvPath}?search=refactor&state=opened`,
|
||||
issuableCount: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
expect(findCsvImportExportButtons().props()).toMatchObject({
|
||||
exportCsvPath: `${defaultProvide.exportCsvPath}?search=refactor&state=opened`,
|
||||
issuableCount: 1,
|
||||
describe('when user is not signed in', () => {
|
||||
it('does not render', () => {
|
||||
wrapper = mountComponent({ provide: { isSignedIn: false }, mountFn: mount });
|
||||
|
||||
expect(findCsvImportExportButtons().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when in a group context', () => {
|
||||
it('does not render', () => {
|
||||
wrapper = mountComponent({ provide: { isProject: false }, mountFn: mount });
|
||||
|
||||
expect(findCsvImportExportButtons().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user is not signed in', () => {
|
||||
it('does not render', () => {
|
||||
wrapper = mountComponent({ provide: { isSignedIn: false }, mountFn: mount });
|
||||
it('renders RSS button link', () => {
|
||||
wrapper = mountComponent({ mountFn: mountExtended });
|
||||
|
||||
expect(findCsvImportExportButtons().exists()).toBe(false);
|
||||
});
|
||||
expect(findRssButton().attributes('href')).toBe(defaultProvide.rssPath);
|
||||
});
|
||||
|
||||
describe('when in a group context', () => {
|
||||
it('does not render', () => {
|
||||
wrapper = mountComponent({ provide: { isProject: false }, mountFn: mount });
|
||||
it('renders calendar button link', () => {
|
||||
wrapper = mountComponent({ mountFn: mountExtended });
|
||||
|
||||
expect(findCsvImportExportButtons().exists()).toBe(false);
|
||||
});
|
||||
expect(findCalendarButton().attributes('href')).toBe(defaultProvide.calendarPath);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -296,7 +304,7 @@ describe('CE IssuesListApp component', () => {
|
|||
it('renders when user has permissions', () => {
|
||||
wrapper = mountComponent({ provide: { canBulkUpdate: true }, mountFn: mount });
|
||||
|
||||
expect(findGlButtonAt(2).text()).toBe('Edit issues');
|
||||
expect(findGlButton().text()).toBe('Edit issues');
|
||||
});
|
||||
|
||||
it('does not render when user does not have permissions', () => {
|
||||
|
|
@ -309,7 +317,7 @@ describe('CE IssuesListApp component', () => {
|
|||
wrapper = mountComponent({ provide: { canBulkUpdate: true }, mountFn: mount });
|
||||
jest.spyOn(eventHub, '$emit');
|
||||
|
||||
findGlButtonAt(2).vm.$emit('click');
|
||||
findGlButton().vm.$emit('click');
|
||||
await waitForPromises();
|
||||
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('issuables:enableBulkEdit');
|
||||
|
|
@ -320,8 +328,8 @@ describe('CE IssuesListApp component', () => {
|
|||
it('renders when user has permissions', () => {
|
||||
wrapper = mountComponent({ provide: { showNewIssueLink: true }, mountFn: mount });
|
||||
|
||||
expect(findGlButtonAt(2).text()).toBe('New issue');
|
||||
expect(findGlButtonAt(2).attributes('href')).toBe(defaultProvide.newIssuePath);
|
||||
expect(findGlButton().text()).toBe('New issue');
|
||||
expect(findGlButton().attributes('href')).toBe(defaultProvide.newIssuePath);
|
||||
});
|
||||
|
||||
it('does not render when user does not have permissions', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlDisclosureDropdown, GlDisclosureDropdownItem } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import TaskListItemActions from '~/issues/show/components/task_list_item_actions.vue';
|
||||
import eventHub from '~/issues/show/event_hub';
|
||||
|
|
@ -6,9 +6,9 @@ import eventHub from '~/issues/show/event_hub';
|
|||
describe('TaskListItemActions component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findGlDropdown = () => wrapper.findComponent(GlDropdown);
|
||||
const findConvertToTaskItem = () => wrapper.findAllComponents(GlDropdownItem).at(0);
|
||||
const findDeleteItem = () => wrapper.findAllComponents(GlDropdownItem).at(1);
|
||||
const findGlDropdown = () => wrapper.findComponent(GlDisclosureDropdown);
|
||||
const findConvertToTaskItem = () => wrapper.findAllComponents(GlDisclosureDropdownItem).at(0);
|
||||
const findDeleteItem = () => wrapper.findAllComponents(GlDisclosureDropdownItem).at(1);
|
||||
|
||||
const mountComponent = () => {
|
||||
const li = document.createElement('li');
|
||||
|
|
@ -20,6 +20,7 @@ describe('TaskListItemActions component', () => {
|
|||
provide: { canUpdate: true },
|
||||
attachTo: document.querySelector('div'),
|
||||
});
|
||||
wrapper.vm.$refs.dropdown.close = jest.fn();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -30,8 +31,8 @@ describe('TaskListItemActions component', () => {
|
|||
expect(findGlDropdown().props()).toMatchObject({
|
||||
category: 'tertiary',
|
||||
icon: 'ellipsis_v',
|
||||
right: true,
|
||||
text: TaskListItemActions.i18n.taskActions,
|
||||
placement: 'right',
|
||||
toggleText: TaskListItemActions.i18n.taskActions,
|
||||
textSrOnly: true,
|
||||
});
|
||||
});
|
||||
|
|
@ -39,7 +40,7 @@ describe('TaskListItemActions component', () => {
|
|||
it('emits event when `Convert to task` dropdown item is clicked', () => {
|
||||
jest.spyOn(eventHub, '$emit');
|
||||
|
||||
findConvertToTaskItem().vm.$emit('click');
|
||||
findConvertToTaskItem().vm.$emit('action');
|
||||
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('convert-task-list-item', '3:1-3:10');
|
||||
});
|
||||
|
|
@ -47,7 +48,7 @@ describe('TaskListItemActions component', () => {
|
|||
it('emits event when `Delete` dropdown item is clicked', () => {
|
||||
jest.spyOn(eventHub, '$emit');
|
||||
|
||||
findDeleteItem().vm.$emit('click');
|
||||
findDeleteItem().vm.$emit('action');
|
||||
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('delete-task-list-item', '3:1-3:10');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { GlSkeletonLoader, GlSprintf, GlAlert } from '@gitlab/ui';
|
||||
import { GlSkeletonLoader, GlSprintf, GlAlert, GlButton } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql';
|
||||
|
|
@ -16,6 +16,7 @@ import {
|
|||
DELETE_IMAGE_SUCCESS_MESSAGE,
|
||||
DELETE_IMAGE_ERROR_MESSAGE,
|
||||
SORT_FIELDS,
|
||||
SETTINGS_TEXT,
|
||||
} from '~/packages_and_registries/container_registry/explorer/constants';
|
||||
import deleteContainerRepositoryMutation from '~/packages_and_registries/container_registry/explorer/graphql/mutations/delete_container_repository.mutation.graphql';
|
||||
import getContainerRepositoriesDetails from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql';
|
||||
|
|
@ -48,6 +49,7 @@ describe('List Page', () => {
|
|||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
|
||||
const findCliCommands = () => wrapper.findComponent(CliCommands);
|
||||
const findSettingsLink = () => wrapper.findComponent(GlButton);
|
||||
const findProjectEmptyState = () => wrapper.findComponent(ProjectEmptyState);
|
||||
const findGroupEmptyState = () => wrapper.findComponent(GroupEmptyState);
|
||||
const findRegistryHeader = () => wrapper.findComponent(RegistryHeader);
|
||||
|
|
@ -110,6 +112,9 @@ describe('List Page', () => {
|
|||
...dockerCommands,
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: createMockDirective('gl-tooltip'),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -122,6 +127,42 @@ describe('List Page', () => {
|
|||
expect(findRegistryHeader().props()).toMatchObject({
|
||||
imagesCount: 2,
|
||||
metadataLoading: false,
|
||||
helpPagePath: '',
|
||||
hideExpirationPolicyData: false,
|
||||
showCleanupPolicyLink: false,
|
||||
expirationPolicy: {},
|
||||
cleanupPoliciesSettingsPath: '',
|
||||
});
|
||||
});
|
||||
|
||||
describe('link to settings', () => {
|
||||
beforeEach(() => {
|
||||
const config = {
|
||||
showContainerRegistrySettings: true,
|
||||
cleanupPoliciesSettingsPath: 'bar',
|
||||
};
|
||||
mountComponent({ config });
|
||||
});
|
||||
|
||||
it('is rendered', () => {
|
||||
expect(findSettingsLink().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('has the right icon', () => {
|
||||
expect(findSettingsLink().props('icon')).toBe('settings');
|
||||
});
|
||||
|
||||
it('has the right attributes', () => {
|
||||
expect(findSettingsLink().attributes()).toMatchObject({
|
||||
'aria-label': SETTINGS_TEXT,
|
||||
href: 'bar',
|
||||
});
|
||||
});
|
||||
|
||||
it('sets tooltip with right label', () => {
|
||||
const tooltip = getBinding(findSettingsLink().element, 'gl-tooltip');
|
||||
|
||||
expect(tooltip.value).toBe(SETTINGS_TEXT);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -235,6 +276,14 @@ describe('List Page', () => {
|
|||
|
||||
expect(findCliCommands().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('link to settings is not visible', async () => {
|
||||
mountComponent({ resolver, config });
|
||||
|
||||
await waitForApolloRequestRender();
|
||||
|
||||
expect(findSettingsLink().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -105,4 +105,31 @@ describe('MRWidget approvals summary', () => {
|
|||
expect(wrapper.findComponent(UserAvatarList).exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('user avatars list layout', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('does not add top padding initially', () => {
|
||||
const avatarsList = findAvatars();
|
||||
|
||||
expect(avatarsList.classes()).not.toContain('gl-pt-1');
|
||||
});
|
||||
|
||||
it('adds some top padding when the list is expanded', async () => {
|
||||
const avatarsList = findAvatars();
|
||||
await avatarsList.vm.$emit('expanded');
|
||||
|
||||
expect(avatarsList.classes()).toContain('gl-pt-1');
|
||||
});
|
||||
|
||||
it('removes the top padding when the list collapsed', async () => {
|
||||
const avatarsList = findAvatars();
|
||||
await avatarsList.vm.$emit('expanded');
|
||||
await avatarsList.vm.$emit('collapsed');
|
||||
|
||||
expect(avatarsList.classes()).not.toContain('gl-pt-1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -148,6 +148,13 @@ describe('UserAvatarList', () => {
|
|||
expect(links.length).toEqual(TEST_BREAKPOINT);
|
||||
});
|
||||
|
||||
it('does not emit any event on mount', async () => {
|
||||
factory();
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.emitted()).toEqual({});
|
||||
});
|
||||
|
||||
describe('with expand clicked', () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
|
|
@ -160,13 +167,25 @@ describe('UserAvatarList', () => {
|
|||
expect(links.length).toEqual(props.items.length);
|
||||
});
|
||||
|
||||
it('with collapse clicked, it renders avatars up to breakpoint', async () => {
|
||||
clickButton();
|
||||
it('emits the `expanded` event', () => {
|
||||
expect(wrapper.emitted('expanded')).toHaveLength(1);
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
const links = wrapper.findAllComponents(UserAvatarLink);
|
||||
describe('with collapse clicked', () => {
|
||||
beforeEach(() => {
|
||||
clickButton();
|
||||
});
|
||||
|
||||
expect(links.length).toEqual(TEST_BREAKPOINT);
|
||||
it('renders avatars up to breakpoint', async () => {
|
||||
await nextTick();
|
||||
const links = wrapper.findAllComponents(UserAvatarLink);
|
||||
|
||||
expect(links.length).toEqual(TEST_BREAKPOINT);
|
||||
});
|
||||
|
||||
it('emits the `collapsed` event', () => {
|
||||
expect(wrapper.emitted('collapsed')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -129,6 +129,62 @@ RSpec.describe PackagesHelper, feature_category: :package_registry do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#show_container_registry_settings' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:admin) { create(:admin) }
|
||||
|
||||
before do
|
||||
allow(helper).to receive(:current_user) { user }
|
||||
end
|
||||
|
||||
subject { helper.show_container_registry_settings(project) }
|
||||
|
||||
context 'with container registry config enabled' do
|
||||
before do
|
||||
stub_config(registry: { enabled: true })
|
||||
end
|
||||
|
||||
context 'when user has permission' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).with(user, :admin_container_image, project).and_return(true)
|
||||
end
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
end
|
||||
|
||||
context 'when user does not have permission' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).with(user, :admin_container_image, project).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with container registry config disabled' do
|
||||
before do
|
||||
stub_config(registry: { enabled: false })
|
||||
end
|
||||
|
||||
context 'when user has permission' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).with(user, :admin_container_image, project).and_return(true)
|
||||
end
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
context 'when user does not have permission' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).with(user, :admin_container_image, project).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#show_group_package_registry_settings' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ProtectedTag::CreateAccessLevel, feature_category: :source_code_management do
|
||||
include_examples 'protected tag access'
|
||||
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:deploy_key) }
|
||||
end
|
||||
|
|
@ -10,16 +12,6 @@ RSpec.describe ProtectedTag::CreateAccessLevel, feature_category: :source_code_m
|
|||
describe 'validations', :aggregate_failures do
|
||||
let_it_be(:protected_tag) { create(:protected_tag) }
|
||||
|
||||
it 'verifies access levels' do
|
||||
is_expected.to validate_inclusion_of(:access_level).in_array(
|
||||
[
|
||||
Gitlab::Access::MAINTAINER,
|
||||
Gitlab::Access::DEVELOPER,
|
||||
Gitlab::Access::NO_ACCESS
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
context 'when deploy key enabled for the project' do
|
||||
let(:deploy_key) { create(:deploy_key, projects: [protected_tag.project]) }
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ RSpec.shared_examples "updates atom feed link" do |type|
|
|||
it "for #{type}" do
|
||||
sign_in(user)
|
||||
visit path
|
||||
click_button 'Actions', match: :first
|
||||
|
||||
link = find_link('Subscribe to RSS feed')
|
||||
params = CGI.parse(URI.parse(link[:href]).query)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'protected ref access' do |association|
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:protected_ref) { create(association, project: project) } # rubocop:disable Rails/SaveBang
|
||||
|
||||
it { is_expected.to validate_inclusion_of(:access_level).in_array(described_class.allowed_access_levels) }
|
||||
|
||||
it { is_expected.to validate_presence_of(:access_level) }
|
||||
|
||||
context 'when not role?' do
|
||||
before do
|
||||
allow(subject).to receive(:role?).and_return(false)
|
||||
end
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:access_level) }
|
||||
end
|
||||
|
||||
describe '#check_access' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:access_level) { ::Gitlab::Access::DEVELOPER }
|
||||
|
||||
before_all do
|
||||
project.add_maintainer(current_user)
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
association => protected_ref,
|
||||
access_level: access_level
|
||||
)
|
||||
end
|
||||
|
||||
context 'when current_user is nil' do
|
||||
it { expect(subject.check_access(nil)).to eq(false) }
|
||||
end
|
||||
|
||||
context 'when access_level is NO_ACCESS' do
|
||||
let(:access_level) { ::Gitlab::Access::NO_ACCESS }
|
||||
|
||||
it { expect(subject.check_access(current_user)).to eq(false) }
|
||||
end
|
||||
|
||||
context 'when current_user can push_code to project and access_level is permitted' do
|
||||
before do
|
||||
allow(current_user).to receive(:can?).with(:push_code, project).and_return(true)
|
||||
end
|
||||
|
||||
it { expect(subject.check_access(current_user)).to eq(true) }
|
||||
end
|
||||
|
||||
context 'when current_user cannot push_code to project' do
|
||||
before do
|
||||
allow(current_user).to receive(:can?).with(:push_code, project).and_return(false)
|
||||
end
|
||||
|
||||
it { expect(subject.check_access(current_user)).to eq(false) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'protected tag access' do
|
||||
include_examples 'protected ref access', :protected_tag
|
||||
|
||||
let_it_be(:protected_tag) { create(:protected_tag) }
|
||||
|
||||
it { is_expected.to belong_to(:protected_tag) }
|
||||
|
||||
describe '#project' do
|
||||
before do
|
||||
allow(protected_tag).to receive(:project)
|
||||
end
|
||||
|
||||
it 'delegates project to protected_tag association' do
|
||||
described_class.new(protected_tag: protected_tag).project
|
||||
|
||||
expect(protected_tag).to have_received(:project)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue