Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
69eacec239
commit
778ea71394
61 changed files with 1334 additions and 381 deletions
|
@ -40,6 +40,9 @@
|
|||
.if-merge-request-title-update-caches: &if-merge-request-title-update-caches
|
||||
if: '$CI_MERGE_REQUEST_TITLE =~ /UPDATE CACHE/'
|
||||
|
||||
.if-merge-request-title-run-all-rspec: &if-merge-request-title-run-all-rspec
|
||||
if: '$CI_MERGE_REQUEST_TITLE =~ /RUN ALL RSPEC/'
|
||||
|
||||
.if-security-merge-request: &if-security-merge-request
|
||||
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
|
||||
|
||||
|
@ -440,22 +443,27 @@
|
|||
.rails:rules:ee-and-foss-migration:
|
||||
rules:
|
||||
- changes: *db-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-unit:
|
||||
rules:
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-integration:
|
||||
rules:
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-system:
|
||||
rules:
|
||||
- changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-and-foss-fast_spec_helper:
|
||||
rules:
|
||||
- changes: ["config/**/*"]
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:default-refs-code-backstage-qa:
|
||||
rules:
|
||||
|
@ -467,24 +475,28 @@
|
|||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *db-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-unit:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-integration:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *backend-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:ee-only-system:
|
||||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- changes: *code-backstage-patterns
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:as-if-foss-migration:
|
||||
rules:
|
||||
|
@ -530,6 +542,7 @@
|
|||
rules:
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
- <<: *if-merge-request
|
||||
changes: *code-backstage-patterns
|
||||
- <<: *if-master-refs
|
||||
|
@ -556,6 +569,7 @@
|
|||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-master-schedule-2-hourly
|
||||
- <<: *if-merge-request-title-run-all-rspec
|
||||
|
||||
.rails:rules:master-schedule-nightly--code-backstage:
|
||||
rules:
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<script>
|
||||
import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
export default {
|
||||
name: 'DeleteButton',
|
||||
components: {
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
GlModal,
|
||||
},
|
||||
directives: {
|
||||
|
@ -25,7 +26,12 @@ export default {
|
|||
buttonVariant: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
default: 'info',
|
||||
},
|
||||
buttonSize: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'medium',
|
||||
},
|
||||
hasSelectedDesigns: {
|
||||
type: Boolean,
|
||||
|
@ -38,27 +44,38 @@ export default {
|
|||
modalId: uniqueId('design-deletion-confirmation-'),
|
||||
};
|
||||
},
|
||||
modal: {
|
||||
title: s__('DesignManagement|Delete designs confirmation'),
|
||||
actionPrimary: {
|
||||
text: s__('Delete'),
|
||||
attributes: { variant: 'danger' },
|
||||
},
|
||||
actionCancel: {
|
||||
text: s__('Cancel'),
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="gl-display-flex gl-align-items-center gl-h-full">
|
||||
<gl-modal
|
||||
:modal-id="modalId"
|
||||
:title="s__('DesignManagement|Delete designs confirmation')"
|
||||
:ok-title="s__('DesignManagement|Delete')"
|
||||
ok-variant="danger"
|
||||
:title="$options.modal.title"
|
||||
:action-primary="$options.modal.actionPrimary"
|
||||
:action-cancel="$options.modal.actionCancel"
|
||||
@ok="$emit('deleteSelectedDesigns')"
|
||||
>
|
||||
<p>{{ s__('DesignManagement|Are you sure you want to delete the selected designs?') }}</p>
|
||||
</gl-modal>
|
||||
<gl-deprecated-button
|
||||
<gl-button
|
||||
v-gl-modal-directive="modalId"
|
||||
:variant="buttonVariant"
|
||||
:disabled="isDeleting || !hasSelectedDesigns"
|
||||
:size="buttonSize"
|
||||
:class="buttonClass"
|
||||
:disabled="isDeleting || !hasSelectedDesigns"
|
||||
>
|
||||
<slot></slot>
|
||||
</gl-deprecated-button>
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -127,7 +127,7 @@ export default {
|
|||
params: { id: filename },
|
||||
query: $route.query,
|
||||
}"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
>
|
||||
<div class="card-body p-0 d-flex-center overflow-hidden position-relative">
|
||||
<div v-if="icon.name" class="design-event position-absolute">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script>
|
||||
import { GlDeprecatedButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
directives: {
|
||||
|
@ -30,7 +30,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<gl-deprecated-button
|
||||
<gl-button
|
||||
v-gl-tooltip.hover
|
||||
:title="
|
||||
s__(
|
||||
|
@ -39,11 +39,12 @@ export default {
|
|||
"
|
||||
:disabled="isSaving"
|
||||
variant="success"
|
||||
size="small"
|
||||
@click="openFileUpload"
|
||||
>
|
||||
{{ s__('DesignManagement|Upload designs') }}
|
||||
<gl-loading-icon v-if="isSaving" inline class="ml-1" />
|
||||
</gl-deprecated-button>
|
||||
</gl-button>
|
||||
|
||||
<input
|
||||
ref="fileUpload"
|
||||
|
|
|
@ -12,6 +12,12 @@ export default {
|
|||
GlLink,
|
||||
GlSprintf,
|
||||
},
|
||||
props: {
|
||||
hasDesigns: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragCounter: 0,
|
||||
|
@ -76,28 +82,29 @@ export default {
|
|||
>
|
||||
<slot>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
@click="openFileUpload"
|
||||
>
|
||||
<div class="d-flex-center flex-column text-center">
|
||||
<gl-icon name="doc-new" :size="48" class="mb-4" />
|
||||
<p>
|
||||
<gl-sprintf
|
||||
:message="
|
||||
__(
|
||||
'%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}.',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #lineOne="{ content }"
|
||||
><span class="d-block">{{ content }}</span>
|
||||
</template>
|
||||
|
||||
<template #link="{ content }">
|
||||
<gl-link class="h-100 w-100" @click.stop="openFileUpload">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<div
|
||||
:class="{ 'gl-flex-direction-column': hasDesigns }"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon name="upload" :size="24" :class="hasDesigns ? 'gl-mb-2' : 'gl-mr-4'" />
|
||||
<gl-sprintf
|
||||
:message="
|
||||
__(
|
||||
'%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}',
|
||||
)
|
||||
"
|
||||
>
|
||||
<template #content="{ content }">
|
||||
<span class="gl-font-weight-bold">{{ content }} </span>
|
||||
</template>
|
||||
<template #link="{ content }">
|
||||
<gl-link @click.stop="openFileUpload">{{ content }}</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -117,7 +124,7 @@ export default {
|
|||
class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
|
||||
>
|
||||
<div v-show="!isDragDataValid" class="mw-50 text-center">
|
||||
<h3>{{ __('Oh no!') }}</h3>
|
||||
<h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('Oh no!') }}</h3>
|
||||
<span>{{
|
||||
__(
|
||||
'You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.',
|
||||
|
@ -125,7 +132,7 @@ export default {
|
|||
}}</span>
|
||||
</div>
|
||||
<div v-show="isDragDataValid" class="mw-50 text-center">
|
||||
<h3>{{ __('Incoming!') }}</h3>
|
||||
<h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('Incoming!') }}</h3>
|
||||
<span>{{ __('Drop your designs to start your upload.') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<script>
|
||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlNewDropdown, GlNewDropdownItem } from '@gitlab/ui';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import allVersionsMixin from '../../mixins/all_versions';
|
||||
import { findVersionId } from '../../utils/design_management_utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlNewDropdown,
|
||||
GlNewDropdownItem,
|
||||
},
|
||||
mixins: [allVersionsMixin],
|
||||
computed: {
|
||||
|
@ -50,8 +50,8 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-dropdown :text="dropdownText" variant="link" class="design-version-dropdown">
|
||||
<gl-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
|
||||
<gl-new-dropdown :text="dropdownText" size="small" class="design-version-dropdown">
|
||||
<gl-new-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
|
||||
<router-link
|
||||
class="d-flex js-version-link"
|
||||
:to="{ path: $route.path, query: { version: findVersionId(version.node.id) } }"
|
||||
|
@ -71,6 +71,6 @@ export default {
|
|||
class="fa fa-check pull-right"
|
||||
></i>
|
||||
</router-link>
|
||||
</gl-dropdown-item>
|
||||
</gl-dropdown>
|
||||
</gl-new-dropdown-item>
|
||||
</gl-new-dropdown>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlLoadingIcon, GlDeprecatedButton, GlAlert } from '@gitlab/ui';
|
||||
import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import UploadButton from '../components/upload/button.vue';
|
||||
|
@ -33,7 +33,7 @@ export default {
|
|||
components: {
|
||||
GlLoadingIcon,
|
||||
GlAlert,
|
||||
GlDeprecatedButton,
|
||||
GlButton,
|
||||
UploadButton,
|
||||
Design,
|
||||
DesignDestroyer,
|
||||
|
@ -96,6 +96,14 @@ export default {
|
|||
? s__('DesignManagement|Deselect all')
|
||||
: s__('DesignManagement|Select all');
|
||||
},
|
||||
isDesignListEmpty() {
|
||||
return !this.isSaving && !this.hasDesigns;
|
||||
},
|
||||
designDropzoneWrapperClass() {
|
||||
return this.isDesignListEmpty
|
||||
? 'col-12'
|
||||
: 'gl-flex-direction-column col-md-6 col-lg-3 gl-mb-3';
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.toggleOnPasteListener(this.$route.name);
|
||||
|
@ -259,18 +267,22 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div data-testid="designs-root">
|
||||
<div data-testid="designs-root" class="gl-mt-2">
|
||||
<header v-if="showToolbar" class="row-content-block border-top-0 p-2 d-flex">
|
||||
<div class="d-flex justify-content-between align-items-center w-100">
|
||||
<design-version-dropdown />
|
||||
<div :class="['qa-selector-toolbar', { 'd-flex': hasDesigns, 'd-none': !hasDesigns }]">
|
||||
<gl-deprecated-button
|
||||
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full">
|
||||
<div>
|
||||
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
|
||||
<design-version-dropdown />
|
||||
</div>
|
||||
<div v-show="hasDesigns" class="qa-selector-toolbar gl-display-flex">
|
||||
<gl-button
|
||||
v-if="isLatestVersion"
|
||||
variant="link"
|
||||
class="mr-2 js-select-all"
|
||||
size="small"
|
||||
class="gl-mr-2 js-select-all"
|
||||
@click="toggleDesignsSelection"
|
||||
>{{ selectAllButtonText }}</gl-deprecated-button
|
||||
>
|
||||
>{{ selectAllButtonText }}
|
||||
</gl-button>
|
||||
<design-destroyer
|
||||
#default="{ mutate, loading }"
|
||||
:filenames="selectedDesigns"
|
||||
|
@ -280,7 +292,9 @@ export default {
|
|||
<delete-button
|
||||
v-if="isLatestVersion"
|
||||
:is-deleting="loading"
|
||||
button-class="btn-danger btn-inverted mr-2"
|
||||
button-variant="danger"
|
||||
button-class="gl-mr-4"
|
||||
button-size="small"
|
||||
:has-selected-designs="hasSelectedDesigns"
|
||||
@deleteSelectedDesigns="mutate()"
|
||||
>
|
||||
|
@ -298,11 +312,22 @@ export default {
|
|||
{{ __('An error occurred while loading designs. Please try again.') }}
|
||||
</gl-alert>
|
||||
<ol v-else class="list-unstyled row">
|
||||
<li class="col-md-6 col-lg-4 mb-3">
|
||||
<design-dropzone class="design-list-item" @change="onUploadDesign" />
|
||||
<span
|
||||
v-if="isDesignListEmpty && !allVersions.length"
|
||||
class="gl-font-weight-bold gl-font-weight-bold gl-ml-5 gl-mb-4"
|
||||
>{{ s__('DesignManagement|Designs') }}</span
|
||||
>
|
||||
<li :class="designDropzoneWrapperClass" data-testid="design-dropzone-wrapper">
|
||||
<design-dropzone
|
||||
:class="{ 'design-list-item design-list-item-new': !isDesignListEmpty }"
|
||||
:has-designs="hasDesigns"
|
||||
@change="onUploadDesign"
|
||||
/>
|
||||
</li>
|
||||
<li v-for="design in designs" :key="design.id" class="col-md-6 col-lg-4 mb-3">
|
||||
<design-dropzone @change="onExistingDesignDropzoneChange($event, design.filename)"
|
||||
<li v-for="design in designs" :key="design.id" class="col-md-6 col-lg-3 gl-mb-3">
|
||||
<design-dropzone
|
||||
:has-designs="hasDesigns"
|
||||
@change="onExistingDesignDropzoneChange($event, design.filename)"
|
||||
><design v-bind="design" :is-uploading="isDesignToBeSaved(design.filename)"
|
||||
/></design-dropzone>
|
||||
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
<script>
|
||||
import {
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
GlIcon,
|
||||
GlFormGroup,
|
||||
GlFormCheckbox,
|
||||
GlNewDropdown,
|
||||
GlNewDropdownItem,
|
||||
} from '@gitlab/ui';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { refreshCurrentPage } from '~/lib/utils/url_utility';
|
||||
import createFlash from '~/flash';
|
||||
import {
|
||||
I18N_ALERT_SETTINGS_FORM,
|
||||
NO_ISSUE_TEMPLATE_SELECTED,
|
||||
TAKING_INCIDENT_ACTION_DOCS_LINK,
|
||||
ISSUE_TEMPLATES_DOCS_LINK,
|
||||
ERROR_MSG,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
GlSprintf,
|
||||
GlLink,
|
||||
GlFormGroup,
|
||||
GlIcon,
|
||||
GlFormCheckbox,
|
||||
GlNewDropdown,
|
||||
GlNewDropdownItem,
|
||||
},
|
||||
inject: ['alertSettings', 'operationsSettingsEndpoint'],
|
||||
data() {
|
||||
return {
|
||||
templates: [NO_ISSUE_TEMPLATE_SELECTED, ...this.alertSettings.templates],
|
||||
createIssueEnabled: this.alertSettings.createIssue,
|
||||
issueTemplate: this.alertSettings.issueTemplateKey,
|
||||
sendEmailEnabled: this.alertSettings.sendEmail,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
i18n: I18N_ALERT_SETTINGS_FORM,
|
||||
TAKING_INCIDENT_ACTION_DOCS_LINK,
|
||||
ISSUE_TEMPLATES_DOCS_LINK,
|
||||
computed: {
|
||||
issueTemplateHeader() {
|
||||
return this.issueTemplate || NO_ISSUE_TEMPLATE_SELECTED.name;
|
||||
},
|
||||
formData() {
|
||||
return {
|
||||
create_issue: this.createIssueEnabled,
|
||||
issue_template_key: this.issueTemplate,
|
||||
send_email: this.sendEmailEnabled,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectIssueTemplate(templateKey) {
|
||||
this.issueTemplate = templateKey;
|
||||
},
|
||||
isTemplateSelected(templateKey) {
|
||||
return templateKey === this.issueTemplate;
|
||||
},
|
||||
updateAlertsIntegrationSettings() {
|
||||
this.loading = true;
|
||||
return axios
|
||||
.patch(this.operationsSettingsEndpoint, {
|
||||
project: {
|
||||
incident_management_setting_attributes: this.formData,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
refreshCurrentPage();
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const message = response?.data?.message || '';
|
||||
|
||||
createFlash(`${ERROR_MSG} ${message}`, 'alert');
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p>
|
||||
<gl-sprintf :message="$options.i18n.introText">
|
||||
<template #docsLink>
|
||||
<gl-link :href="$options.TAKING_INCIDENT_ACTION_DOCS_LINK" target="_blank">
|
||||
<span>{{ $options.i18n.introLinkText }}</span>
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</p>
|
||||
<form ref="settingsForm" @submit.prevent="updateAlertsIntegrationSettings">
|
||||
<gl-form-group class="gl-pl-0">
|
||||
<gl-form-checkbox v-model="createIssueEnabled" data-qa-selector="create_issue_checkbox">
|
||||
<span>{{ $options.i18n.createIssue.label }}</span>
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
label-size="sm"
|
||||
label-for="alert-integration-settings-issue-template"
|
||||
class="col-8 col-md-9 gl-px-6"
|
||||
>
|
||||
<label class="gl-display-inline-flex" for="alert-integration-settings-issue-template">
|
||||
{{ $options.i18n.issueTemplate.label }}
|
||||
<gl-link :href="$options.ISSUE_TEMPLATES_DOCS_LINK" target="_blank">
|
||||
<gl-icon name="question" :size="12" />
|
||||
</gl-link>
|
||||
</label>
|
||||
<gl-new-dropdown
|
||||
id="alert-integration-settings-issue-template"
|
||||
data-qa-selector="incident_templates_dropdown"
|
||||
:text="issueTemplateHeader"
|
||||
:block="true"
|
||||
>
|
||||
<gl-new-dropdown-item
|
||||
v-for="template in templates"
|
||||
:key="template.key"
|
||||
data-qa-selector="incident_templates_item"
|
||||
:is-check-item="true"
|
||||
:is-checked="isTemplateSelected(template.key)"
|
||||
@click="selectIssueTemplate(template.key)"
|
||||
>
|
||||
{{ template.name }}
|
||||
</gl-new-dropdown-item>
|
||||
</gl-new-dropdown>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group class="gl-pl-0 gl-mb-5">
|
||||
<gl-form-checkbox v-model="sendEmailEnabled">
|
||||
<span>{{ $options.i18n.sendEmail.label }}</span>
|
||||
</gl-form-checkbox>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-button
|
||||
ref="submitBtn"
|
||||
data-qa-selector="save_changes_button"
|
||||
:disabled="loading"
|
||||
variant="success"
|
||||
type="submit"
|
||||
class="js-no-auto-disable"
|
||||
>
|
||||
{{ $options.i18n.saveBtnLabel }}
|
||||
</gl-button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,49 @@
|
|||
<script>
|
||||
import { GlButton, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import AlertsSettingsForm from './alerts_form.vue';
|
||||
import { INTEGRATION_TABS_CONFIG, I18N_INTEGRATION_TABS } from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
AlertsSettingsForm,
|
||||
},
|
||||
tabs: INTEGRATION_TABS_CONFIG,
|
||||
i18n: I18N_INTEGRATION_TABS,
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="incident-management-settings"
|
||||
data-qa-selector="incidents_settings_content"
|
||||
class="settings no-animate qa-incident-management-settings"
|
||||
>
|
||||
<div class="settings-header">
|
||||
<h3 ref="sectionHeader" class="h4">
|
||||
{{ $options.i18n.headerText }}
|
||||
</h3>
|
||||
<gl-button ref="toggleBtn" class="js-settings-toggle">{{
|
||||
$options.i18n.expandBtnLabel
|
||||
}}</gl-button>
|
||||
<p ref="sectionSubHeader">
|
||||
{{ $options.i18n.subHeaderText }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="settings-content">
|
||||
<gl-tabs>
|
||||
<gl-tab
|
||||
v-for="(tab, index) in $options.tabs"
|
||||
v-if="tab.active"
|
||||
:key="`${tab.title}_${index}`"
|
||||
:title="tab.title"
|
||||
>
|
||||
<component :is="tab.component" class="gl-pt-3" :data-testid="`${tab.component}-tab`" />
|
||||
</gl-tab>
|
||||
</gl-tabs>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
51
app/assets/javascripts/incidents_settings/constants.js
Normal file
51
app/assets/javascripts/incidents_settings/constants.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { __, s__ } from '~/locale';
|
||||
|
||||
export const INTEGRATION_TABS_CONFIG = [
|
||||
{
|
||||
title: s__('IncidentSettings|Alert integration'),
|
||||
component: 'AlertsSettingsForm',
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: s__('IncidentSettings|PagerDuty integration'),
|
||||
component: '',
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
title: s__('IncidentSettings|Grafana integration'),
|
||||
component: '',
|
||||
active: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const I18N_INTEGRATION_TABS = {
|
||||
headerText: s__('IncidentSettings|Incidents'),
|
||||
expandBtnLabel: __('Expand'),
|
||||
saveBtnLabel: __('Save changes'),
|
||||
subHeaderText: s__(
|
||||
'IncidentSettings|Set up integrations with external tools to help better manage incidents.',
|
||||
),
|
||||
};
|
||||
|
||||
export const I18N_ALERT_SETTINGS_FORM = {
|
||||
saveBtnLabel: __('Save changes'),
|
||||
introText: __('Action to take when receiving an alert. %{docsLink}'),
|
||||
introLinkText: __('More information.'),
|
||||
createIssue: {
|
||||
label: __('Create an issue. Issues are created for each alert triggered.'),
|
||||
},
|
||||
issueTemplate: {
|
||||
label: __('Issue template (optional)'),
|
||||
},
|
||||
sendEmail: {
|
||||
label: __('Send a separate email notification to Developers.'),
|
||||
},
|
||||
};
|
||||
|
||||
export const NO_ISSUE_TEMPLATE_SELECTED = { key: '', name: __('No template selected') };
|
||||
export const TAKING_INCIDENT_ACTION_DOCS_LINK =
|
||||
'/help/user/project/integrations/prometheus#taking-action-on-incidents-ultimate';
|
||||
export const ISSUE_TEMPLATES_DOCS_LINK =
|
||||
'/help/user/project/description_templates#creating-issue-templates';
|
||||
|
||||
export const ERROR_MSG = __('There was an error saving your changes.');
|
31
app/assets/javascripts/incidents_settings/index.js
Normal file
31
app/assets/javascripts/incidents_settings/index.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import Vue from 'vue';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import SettingsTabs from './components/incidents_settings_tabs.vue';
|
||||
|
||||
export default () => {
|
||||
const el = document.querySelector('.js-incidents-settings');
|
||||
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
dataset: { operationsSettingsEndpoint, templates, createIssue, issueTemplateKey, sendEmail },
|
||||
} = el;
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
provide: {
|
||||
operationsSettingsEndpoint,
|
||||
alertSettings: {
|
||||
templates: JSON.parse(templates),
|
||||
createIssue: parseBoolean(createIssue),
|
||||
issueTemplateKey,
|
||||
sendEmail: parseBoolean(sendEmail),
|
||||
},
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement(SettingsTabs);
|
||||
},
|
||||
});
|
||||
};
|
|
@ -3,8 +3,10 @@ import mountAlertsSettings from '~/alerts_settings';
|
|||
import mountOperationSettings from '~/operation_settings';
|
||||
import mountGrafanaIntegration from '~/grafana_integration';
|
||||
import initSettingsPanels from '~/settings_panels';
|
||||
import initIncidentsSettings from '~/incidents_settings';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initIncidentsSettings();
|
||||
mountErrorTrackingForm();
|
||||
mountOperationSettings();
|
||||
mountGrafanaIntegration();
|
||||
|
|
|
@ -17,3 +17,8 @@
|
|||
height: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
// This is temporary class to be removed after feature flag removal: https://gitlab.com/gitlab-org/gitlab/-/issues/223197
|
||||
.design-list-item-new {
|
||||
height: 210px;
|
||||
}
|
||||
|
|
|
@ -935,11 +935,10 @@ table.code {
|
|||
}
|
||||
}
|
||||
|
||||
.files:not([data-can-create-note='true']) .frame {
|
||||
.files:not([data-can-create-note]) .frame {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.frame,
|
||||
.frame.click-to-comment,
|
||||
.btn-transparent.image-diff-overlay-add-comment {
|
||||
position: relative;
|
||||
|
|
|
@ -11,7 +11,9 @@ module Projects
|
|||
|
||||
class << self
|
||||
def valid_params
|
||||
@valid_params ||= %i[page per_page search state]
|
||||
@valid_params ||= %i[page per_page search state status author_username assignee_username]
|
||||
# to permit array params you need to init them to an empty array
|
||||
@valid_params << { labels: [] }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ module Jira
|
|||
extend ::Gitlab::Utils::Override
|
||||
|
||||
PER_PAGE = 100
|
||||
DEFAULT_FIELDS = %w[assignee created creator id issuetype key
|
||||
labels priority project reporter resolutiondate
|
||||
status statuscategorychangeddate summary updated].join(',').freeze
|
||||
|
||||
def initialize(jira_service, params = {})
|
||||
super(jira_service, params)
|
||||
|
@ -22,7 +25,7 @@ module Jira
|
|||
|
||||
override :url
|
||||
def url
|
||||
"#{base_api_url}/search?jql=#{CGI.escape(jql)}&startAt=#{start_at}&maxResults=#{per_page}&fields=*all"
|
||||
"#{base_api_url}/search?jql=#{CGI.escape(jql)}&startAt=#{start_at}&maxResults=#{per_page}&fields=#{DEFAULT_FIELDS}"
|
||||
end
|
||||
|
||||
override :build_service_response
|
||||
|
|
|
@ -14,7 +14,7 @@ module Spam
|
|||
end
|
||||
|
||||
def execute
|
||||
external_spam_check_result = spam_verdict
|
||||
external_spam_check_result = external_verdict
|
||||
akismet_result = akismet_verdict
|
||||
|
||||
# filter out anything we don't recognise, including nils.
|
||||
|
@ -38,7 +38,7 @@ module Spam
|
|||
end
|
||||
end
|
||||
|
||||
def spam_verdict
|
||||
def external_verdict
|
||||
return unless Gitlab::CurrentSettings.spam_check_endpoint_enabled
|
||||
return if endpoint_url.blank?
|
||||
|
||||
|
|
|
@ -4,15 +4,24 @@
|
|||
- else
|
||||
.js-design-management{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
|
||||
- else
|
||||
.mt-4
|
||||
.row.empty-state
|
||||
.col-12
|
||||
.text-content
|
||||
%h4.center
|
||||
= _('The one place for your designs')
|
||||
%p.center
|
||||
- requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements')
|
||||
- requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url }
|
||||
- support_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: support_url }
|
||||
- link_end = '</a>'.html_safe
|
||||
= s_("DesignManagement|To enable design management, you'll need to %{requirements_link_start}meet the requirements%{requirements_link_end}. If you need help, reach out to our %{support_link_start}support team%{support_link_end} for assistance.").html_safe % { requirements_link_start: requirements_link_start, requirements_link_end: link_end, support_link_start: support_link_start, support_link_end: link_end }
|
||||
- if Feature.enabled?(:design_management_moved, @project)
|
||||
.row.empty-state.design-dropzone-border.gl-mt-5
|
||||
.text-content.center.gl-font-weight-bold
|
||||
- requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements')
|
||||
- requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url }
|
||||
- support_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: support_url }
|
||||
- link_end = '</a>'.html_safe
|
||||
= s_("DesignManagement|To enable design management, you'll need to %{requirements_link_start}meet the requirements%{requirements_link_end}. If you need help, reach out to our %{support_link_start}support team%{support_link_end} for assistance.").html_safe % { requirements_link_start: requirements_link_start, requirements_link_end: link_end, support_link_start: support_link_start, support_link_end: link_end }
|
||||
- else
|
||||
.mt-4
|
||||
.row.empty-state
|
||||
.col-12
|
||||
.text-content
|
||||
%h4.center
|
||||
= _('The one place for your designs')
|
||||
%p.center
|
||||
- requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements')
|
||||
- requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url }
|
||||
- support_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: support_url }
|
||||
- link_end = '</a>'.html_safe
|
||||
= s_("DesignManagement|To enable design management, you'll need to %{requirements_link_start}meet the requirements%{requirements_link_end}. If you need help, reach out to our %{support_link_start}support team%{support_link_end} for assistance.").html_safe % { requirements_link_start: requirements_link_start, requirements_link_end: link_end, support_link_start: support_link_start, support_link_end: link_end }
|
||||
|
|
|
@ -1,32 +1,8 @@
|
|||
- templates = []
|
||||
- setting = project_incident_management_setting
|
||||
- templates = setting.available_issue_templates.map { |t| [t.name, t.key] }
|
||||
- templates = setting.available_issue_templates.map { |t| { key: t.key, name: t.name } }
|
||||
|
||||
%section.settings.no-animate.qa-incident-management-settings{ data: { qa_selector: 'incidents_settings_content' } }
|
||||
.settings-header
|
||||
%h3{ :class => "h4" }= _('Incidents')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= _('Expand')
|
||||
%p
|
||||
= _('Action to take when receiving an alert.')
|
||||
= link_to help_page_path('user/project/integrations/prometheus', anchor: 'taking-action-on-incidents-ultimate') do
|
||||
= _('More information')
|
||||
.settings-content
|
||||
= form_for @project, url: project_settings_operations_path(@project), method: :patch do |f|
|
||||
= form_errors(@project.incident_management_setting)
|
||||
.form-group
|
||||
= f.fields_for :incident_management_setting_attributes, setting do |form|
|
||||
.form-group
|
||||
= form.check_box :create_issue, data: { qa_selector: 'create_issue_checkbox' }
|
||||
= form.label :create_issue, _('Create an issue. Issues are created for each alert triggered.'), class: 'form-check-label'
|
||||
.form-group.col-sm-8
|
||||
= form.label :issue_template_key, class: 'label-bold' do
|
||||
= _('Issue template (optional)')
|
||||
= link_to icon('question-circle'), help_page_path('user/project/description_templates', anchor: 'creating-issue-templates'), target: '_blank', rel: 'noopener noreferrer'
|
||||
.select-wrapper
|
||||
= form.select :issue_template_key, templates, {include_blank: 'No template selected'}, class: "form-control select-control", data: { qa_selector: 'incident_templates_dropdown' }
|
||||
= icon('chevron-down')
|
||||
.form-group
|
||||
= form.check_box :send_email
|
||||
= form.label :send_email, _('Send a separate email notification to Developers.'), class: 'form-check-label'
|
||||
= f.submit _('Save changes'), class: 'btn btn-success', data: { qa_selector: 'save_changes_button' }
|
||||
.js-incidents-settings{ data: { operations_settings_endpoint: project_settings_operations_path(@project),
|
||||
templates: templates.to_json,
|
||||
create_issue: setting.create_issue.to_s,
|
||||
issue_template_key: setting.issue_template_key.to_s,
|
||||
send_email: setting.send_email.to_s } }
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Move alert integrations setting to Vue
|
||||
merge_request: 36110
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix to remove speech bubble on hover over image on MR Overview tab
|
||||
merge_request: 36474
|
||||
author: Adam Alvis @adamalvis
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix to display speech bubble on hover over image on commits page
|
||||
merge_request: 36470
|
||||
author: Adam Alvis @adamalvis
|
||||
type: fixed
|
|
@ -387,6 +387,11 @@ We follow the [PostgreSQL versions shipped with Omnibus GitLab](https://docs.git
|
|||
Consult [GitLab tests in the Continuous Integration (CI) context](testing_guide/ci.md)
|
||||
for more information.
|
||||
|
||||
We have dedicated jobs for each [testing level](testing_guide/testing_levels.md) and each job runs depending on the
|
||||
changes made in your merge request.
|
||||
If you want to force all the RSpec jobs to run regardless of your changes, you can include `RUN ALL RSPEC` in your merge
|
||||
request title.
|
||||
|
||||
### Review app jobs
|
||||
|
||||
Consult the [Review Apps](testing_guide/review_apps.md) dedicated page for more information.
|
||||
|
|
|
@ -296,14 +296,16 @@ An approval is optional when a security report:
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13067) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.3.
|
||||
|
||||
To enable License Approvals, a [project approval rule](../project/merge_requests/merge_request_approvals.md#multiple-approval-rules-premium)
|
||||
must be created with the case-sensitive name `License-Check`. This approval group must be set
|
||||
with the number of approvals required greater than zero.
|
||||
`License-Check` is an approval rule you can enable to allow an individual or group to approve a
|
||||
merge request that contains a `denied` license.
|
||||
|
||||
Once this group is added to your project, the approval rule is enabled for all Merge Requests. To
|
||||
configure how this rule behaves, you can choose which licenses to `allow` or `deny` in the
|
||||
[project policies for License Compliance](../compliance/license_compliance/index.md#policies)
|
||||
section.
|
||||
You can enable `License-Check` one of two ways:
|
||||
|
||||
- Create a [project approval rule](../project/merge_requests/merge_request_approvals.md#multiple-approval-rules-premium)
|
||||
with the case-sensitive name `License-Check`.
|
||||
- Create an approval group in the [project policies section for License Compliance](../compliance/license_compliance/index.md#policies).
|
||||
You must set this approval group's number of approvals required to greater than zero. Once you
|
||||
enable this group in your project, the approval rule is enabled for all merge requests.
|
||||
|
||||
Any code changes cause the approvals required to reset.
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
Before Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -46,7 +46,7 @@ When GitLab detects a **Denied** license, you can view it in the [license list](
|
|||
|
||||
You can view and modify existing policies from the [policies](#policies) tab.
|
||||
|
||||
![Edit Policy](img/policies_maintainer_edit_v13_0.png)
|
||||
![Edit Policy](img/policies_maintainer_edit_v13_2.png)
|
||||
|
||||
## Use cases
|
||||
|
||||
|
@ -657,34 +657,39 @@ and the associated classifications for each.
|
|||
|
||||
Policies can be configured by maintainers of the project.
|
||||
|
||||
![Edit Policy](img/policies_maintainer_edit_v13_0.png)
|
||||
![Add Policy](img/policies_maintainer_add_v13_0.png)
|
||||
![Edit Policy](img/policies_maintainer_edit_v13_2.png)
|
||||
![Add Policy](img/policies_maintainer_add_v13_2.png)
|
||||
|
||||
Developers of the project can view the policies configured in a project.
|
||||
|
||||
![View Policies](img/policies_v13_0.png)
|
||||
|
||||
## License Compliance report under pipelines
|
||||
### Enabling License Approvals within a project
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5491) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.2.
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13067) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.3.
|
||||
|
||||
From your project's left sidebar, navigate to **CI/CD > Pipelines** and click on the
|
||||
pipeline ID that has a `license_scanning` job to see the Licenses tab with the listed
|
||||
licenses (if any).
|
||||
`License-Check` is an approval rule you can enable to allow an approver, individual, or group to
|
||||
approve a merge request that contains a `denied` license.
|
||||
|
||||
![License Compliance Pipeline Tab](img/license_compliance_pipeline_tab_v13_0.png)
|
||||
You can enable `License-Check` one of two ways:
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
- Create a [project approval rule](../../project/merge_requests/merge_request_approvals.md#multiple-approval-rules-premium)
|
||||
with the case-sensitive name `License-Check`.
|
||||
- Create an approval group in the [project policies section for License Compliance](#policies).
|
||||
You must set this approval group's number of approvals required to greater than zero. Once you
|
||||
enable this group in your project, the approval rule is enabled for all merge requests.
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
Any code changes cause the approvals required to reset.
|
||||
|
||||
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
An approval is required when a license report:
|
||||
|
||||
- Contains a dependency that includes a software license that is `denied`.
|
||||
- Is not generated during pipeline execution.
|
||||
|
||||
An approval is optional when a license report:
|
||||
|
||||
- Contains no software license violations.
|
||||
- Contains only new licenses that are `allowed` or unknown.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ module API
|
|||
|
||||
# Helper Methods for Grape Endpoint
|
||||
module HelperMethods
|
||||
prepend_if_ee('EE::API::APIGuard::HelperMethods') # rubocop: disable Cop/InjectEnterpriseEditionModule
|
||||
include Gitlab::Auth::AuthFinders
|
||||
|
||||
def access_token
|
||||
|
@ -66,7 +65,7 @@ module API
|
|||
|
||||
def find_user_from_sources
|
||||
deploy_token_from_request ||
|
||||
find_user_from_access_token ||
|
||||
find_user_from_bearer_token ||
|
||||
find_user_from_job_token ||
|
||||
find_user_from_warden
|
||||
end
|
||||
|
|
|
@ -41,6 +41,16 @@ module API
|
|||
end
|
||||
end
|
||||
|
||||
def job_token_authentication?
|
||||
initial_current_user && @current_authenticated_job.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
end
|
||||
|
||||
# Returns the job associated with the token provided for
|
||||
# authentication, if any
|
||||
def current_authenticated_job
|
||||
@current_authenticated_job
|
||||
end
|
||||
|
||||
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
# We can't rewrite this with StrongMemoize because `sudo!` would
|
||||
# actually write to `@current_user`, and `sudo?` would immediately
|
||||
|
|
|
@ -54,6 +54,11 @@ module Gitlab
|
|||
User.find_by_feed_token(token) || raise(UnauthorizedError)
|
||||
end
|
||||
|
||||
def find_user_from_bearer_token
|
||||
find_user_from_job_bearer_token ||
|
||||
find_user_from_access_token
|
||||
end
|
||||
|
||||
def find_user_from_job_token
|
||||
return unless route_authentication_setting[:job_token_allowed]
|
||||
return find_user_from_basic_auth_job if route_authentication_setting[:job_token_allowed] == :basic_auth
|
||||
|
@ -136,6 +141,9 @@ module Gitlab
|
|||
end
|
||||
|
||||
def validate_access_token!(scopes: [])
|
||||
# return early if we've already authenticated via a job token
|
||||
return if @current_authenticated_job.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
# return early if we've already authenticated via a deploy token
|
||||
return if @current_authenticated_deploy_token.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
|
@ -155,6 +163,20 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def find_user_from_job_bearer_token
|
||||
return unless route_authentication_setting[:job_token_allowed]
|
||||
|
||||
token = parsed_oauth_token
|
||||
return unless token
|
||||
|
||||
job = ::Ci::Build.find_by_token(token)
|
||||
return unless job
|
||||
|
||||
@current_authenticated_job = job # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||
|
||||
job.user
|
||||
end
|
||||
|
||||
def route_authentication_setting
|
||||
return {} unless respond_to?(:route_setting)
|
||||
|
||||
|
|
|
@ -299,6 +299,9 @@ msgstr ""
|
|||
msgid "%{containerScanningLinkStart}Container Scanning%{containerScanningLinkEnd} and/or %{dependencyScanningLinkStart}Dependency Scanning%{dependencyScanningLinkEnd} must be enabled. %{securityBotLinkStart}GitLab-Security-Bot%{securityBotLinkEnd} will be the author of the auto-created merge request. %{moreInfoLinkStart}More information%{moreInfoLinkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{cores} cores"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1289,7 +1292,7 @@ msgstr ""
|
|||
msgid "Account: %{account}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Action to take when receiving an alert."
|
||||
msgid "Action to take when receiving an alert. %{docsLink}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Actions"
|
||||
|
@ -7958,6 +7961,9 @@ msgstr ""
|
|||
msgid "DesignManagement|Deselect all"
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|Designs"
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|Discard comment"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8000,7 +8006,7 @@ msgstr ""
|
|||
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|To enable design management, you'll need to %{requirements_link_start}meet the requirements%{requirements_link_end}. If you need help, reach out to our %{support_link_start}support team%{support_link_end} for assistance."
|
||||
msgid "DesignManagement|To enable design management, you'll need to %{requirements_link_start}meet the requirements%{requirements_link_end}. If you need help, reach out to our %{support_link_start}support team%{support_link_end} for assistance."
|
||||
msgstr ""
|
||||
|
||||
msgid "DesignManagement|Unresolve thread"
|
||||
|
@ -12407,7 +12413,19 @@ msgstr ""
|
|||
msgid "Incident Management Limits"
|
||||
msgstr ""
|
||||
|
||||
msgid "Incidents"
|
||||
msgid "IncidentSettings|Alert integration"
|
||||
msgstr ""
|
||||
|
||||
msgid "IncidentSettings|Grafana integration"
|
||||
msgstr ""
|
||||
|
||||
msgid "IncidentSettings|Incidents"
|
||||
msgstr ""
|
||||
|
||||
msgid "IncidentSettings|PagerDuty integration"
|
||||
msgstr ""
|
||||
|
||||
msgid "IncidentSettings|Set up integrations with external tools to help better manage incidents."
|
||||
msgstr ""
|
||||
|
||||
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
|
||||
|
@ -15065,6 +15083,9 @@ msgstr ""
|
|||
msgid "More information is available|here"
|
||||
msgstr ""
|
||||
|
||||
msgid "More information."
|
||||
msgstr ""
|
||||
|
||||
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -15634,6 +15655,9 @@ msgstr ""
|
|||
msgid "No template"
|
||||
msgstr ""
|
||||
|
||||
msgid "No template selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "No test coverage"
|
||||
msgstr ""
|
||||
|
||||
|
@ -25418,9 +25442,24 @@ msgstr ""
|
|||
msgid "User was successfully updated."
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Add"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Add Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Add users"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Cancel"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Define a set of users to be used within feature flag strategies"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|Enter a comma separated list of user IDs. These IDs should be the users of the system in which the feature flag is set, not GitLab IDs"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserLists|There are no users"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.5",
|
||||
"@gitlab/svgs": "1.151.0",
|
||||
"@gitlab/ui": "17.21.0",
|
||||
"@gitlab/ui": "17.22.1",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "^6.0.3-1",
|
||||
"@sentry/browser": "^5.10.2",
|
||||
|
|
|
@ -5,10 +5,11 @@ module QA
|
|||
module Project
|
||||
module Settings
|
||||
class Incidents < Page::Base
|
||||
view 'app/views/projects/settings/operations/_incidents.html.haml' do
|
||||
view 'app/assets/javascripts/incidents_settings/components/alerts_form.vue' do
|
||||
element :create_issue_checkbox
|
||||
element :incident_templates_dropdown
|
||||
element :save_changes_button
|
||||
element :incident_templates_item
|
||||
end
|
||||
|
||||
def enable_issues_for_incidents
|
||||
|
@ -16,8 +17,9 @@ module QA
|
|||
end
|
||||
|
||||
def select_issue_template(template)
|
||||
click_element(:incident_templates_dropdown)
|
||||
within_element :incident_templates_dropdown do
|
||||
find(:option, template).select_option
|
||||
find_element(:incident_templates_item, text: template).click
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ module QA
|
|||
class Operations < Page::Base
|
||||
include QA::Page::Settings::Common
|
||||
|
||||
view 'app/views/projects/settings/operations/_incidents.html.haml' do
|
||||
view 'app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue' do
|
||||
element :incidents_settings_content
|
||||
end
|
||||
|
||||
|
|
|
@ -45,15 +45,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
|||
|
||||
it 'updates form values' do
|
||||
check(create_issue)
|
||||
template_select = find_field('Issue template')
|
||||
template_select.find(:xpath, 'option[2]').select_option
|
||||
uncheck(send_email)
|
||||
|
||||
save_form
|
||||
click_expand_incident_management_button
|
||||
|
||||
expect(find_field(create_issue)).to be_checked
|
||||
expect(page).to have_select('Issue template', selected: 'bug')
|
||||
expect(find_field(send_email)).not_to be_checked
|
||||
end
|
||||
|
||||
|
@ -64,7 +61,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
|||
end
|
||||
|
||||
def save_form
|
||||
page.within "#edit_project_#{project.id}" do
|
||||
page.within ".qa-incident-management-settings" do
|
||||
click_on 'Save changes'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
||||
import BatchDeleteButton from '~/design_management_new/components/delete_button.vue';
|
||||
|
||||
describe('Batch delete button component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findButton = () => wrapper.find(GlDeprecatedButton);
|
||||
const findButton = () => wrapper.find(GlButton);
|
||||
const findModal = () => wrapper.find(GlModal);
|
||||
|
||||
function createComponent(isDeleting = false) {
|
||||
|
|
|
@ -10,7 +10,7 @@ exports[`Design management list item component when item appears in view after i
|
|||
|
||||
exports[`Design management list item component with no notes renders item with correct status icon for creation event 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -78,7 +78,7 @@ exports[`Design management list item component with no notes renders item with c
|
|||
|
||||
exports[`Design management list item component with no notes renders item with correct status icon for deletion event 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -146,7 +146,7 @@ exports[`Design management list item component with no notes renders item with c
|
|||
|
||||
exports[`Design management list item component with no notes renders item with correct status icon for modification event 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -214,7 +214,7 @@ exports[`Design management list item component with no notes renders item with c
|
|||
|
||||
exports[`Design management list item component with no notes renders item with no status icon for none event 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -269,7 +269,7 @@ exports[`Design management list item component with no notes renders item with n
|
|||
|
||||
exports[`Design management list item component with no notes renders loading spinner when isUploading is true 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -329,7 +329,7 @@ exports[`Design management list item component with no notes renders loading spi
|
|||
|
||||
exports[`Design management list item component with notes renders item with multiple comments 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
@ -401,7 +401,7 @@ exports[`Design management list item component with notes renders item with mult
|
|||
|
||||
exports[`Design management list item component with notes renders item with single comment 1`] = `
|
||||
<router-link-stub
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item"
|
||||
class="card cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
|
||||
to="[object Object]"
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -50,6 +50,7 @@ exports[`Design management toolbar component renders design and updated data 1`]
|
|||
|
||||
<delete-button-stub
|
||||
buttonclass=""
|
||||
buttonsize="medium"
|
||||
buttonvariant="danger"
|
||||
hasselecteddesigns="true"
|
||||
>
|
||||
|
|
|
@ -4,8 +4,10 @@ exports[`Design management upload button component renders inverted upload desig
|
|||
<div
|
||||
isinverted="true"
|
||||
>
|
||||
<gl-deprecated-button-stub
|
||||
size="md"
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
icon=""
|
||||
size="small"
|
||||
title="Adding a design with the same filename replaces the file in a new version."
|
||||
variant="success"
|
||||
>
|
||||
|
@ -13,7 +15,7 @@ exports[`Design management upload button component renders inverted upload desig
|
|||
Upload designs
|
||||
|
||||
<!---->
|
||||
</gl-deprecated-button-stub>
|
||||
</gl-button-stub>
|
||||
|
||||
<input
|
||||
accept="image/*"
|
||||
|
@ -27,9 +29,11 @@ exports[`Design management upload button component renders inverted upload desig
|
|||
|
||||
exports[`Design management upload button component renders loading icon 1`] = `
|
||||
<div>
|
||||
<gl-deprecated-button-stub
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
disabled="true"
|
||||
size="md"
|
||||
icon=""
|
||||
size="small"
|
||||
title="Adding a design with the same filename replaces the file in a new version."
|
||||
variant="success"
|
||||
>
|
||||
|
@ -43,7 +47,7 @@ exports[`Design management upload button component renders loading icon 1`] = `
|
|||
label="Loading"
|
||||
size="sm"
|
||||
/>
|
||||
</gl-deprecated-button-stub>
|
||||
</gl-button-stub>
|
||||
|
||||
<input
|
||||
accept="image/*"
|
||||
|
@ -57,8 +61,10 @@ exports[`Design management upload button component renders loading icon 1`] = `
|
|||
|
||||
exports[`Design management upload button component renders upload design button 1`] = `
|
||||
<div>
|
||||
<gl-deprecated-button-stub
|
||||
size="md"
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
icon=""
|
||||
size="small"
|
||||
title="Adding a design with the same filename replaces the file in a new version."
|
||||
variant="success"
|
||||
>
|
||||
|
@ -66,7 +72,7 @@ exports[`Design management upload button component renders upload design button
|
|||
Upload designs
|
||||
|
||||
<!---->
|
||||
</gl-deprecated-button-stub>
|
||||
</gl-button-stub>
|
||||
|
||||
<input
|
||||
accept="image/*"
|
||||
|
|
|
@ -5,22 +5,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -43,7 +42,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -56,7 +57,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style=""
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -74,22 +77,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -112,7 +114,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -125,7 +129,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style=""
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -143,22 +149,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -180,7 +185,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
<div
|
||||
class="mw-50 text-center"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -193,7 +200,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -211,22 +220,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -248,7 +256,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
<div
|
||||
class="mw-50 text-center"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -261,7 +271,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -279,22 +291,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -316,7 +327,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
<div
|
||||
class="mw-50 text-center"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -329,7 +342,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -347,22 +362,21 @@ exports[`Design management dropzone component when no slot provided renders defa
|
|||
class="w-100 position-relative"
|
||||
>
|
||||
<button
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 d-flex-center p-3"
|
||||
class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
|
||||
>
|
||||
<div
|
||||
class="d-flex-center flex-column text-center"
|
||||
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
|
||||
data-testid="dropzone-area"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="mb-4"
|
||||
name="doc-new"
|
||||
size="48"
|
||||
class="gl-mb-2"
|
||||
name="upload"
|
||||
size="24"
|
||||
/>
|
||||
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
||||
/>
|
||||
</p>
|
||||
<gl-sprintf-stub
|
||||
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
@ -384,7 +398,9 @@ exports[`Design management dropzone component when no slot provided renders defa
|
|||
<div
|
||||
class="mw-50 text-center"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -397,7 +413,9 @@ exports[`Design management dropzone component when no slot provided renders defa
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
@ -428,7 +446,9 @@ exports[`Design management dropzone component when slot provided renders dropzon
|
|||
<div
|
||||
class="mw-50 text-center"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Oh no!
|
||||
</h3>
|
||||
|
||||
|
@ -441,7 +461,9 @@ exports[`Design management dropzone component when slot provided renders dropzon
|
|||
class="mw-50 text-center"
|
||||
style="display: none;"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class=""
|
||||
>
|
||||
Incoming!
|
||||
</h3>
|
||||
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Design management design version dropdown component renders design version dropdown button 1`] = `
|
||||
<gl-dropdown-stub
|
||||
<gl-new-dropdown-stub
|
||||
category="tertiary"
|
||||
class="design-version-dropdown"
|
||||
headertext=""
|
||||
issueiid=""
|
||||
projectpath=""
|
||||
size="small"
|
||||
text="Showing Latest Version"
|
||||
variant="link"
|
||||
variant="default"
|
||||
>
|
||||
<gl-dropdown-item-stub>
|
||||
<gl-new-dropdown-item-stub
|
||||
avatarurl=""
|
||||
iconcolor=""
|
||||
iconname=""
|
||||
iconrightname=""
|
||||
secondarytext=""
|
||||
>
|
||||
<router-link-stub
|
||||
class="d-flex js-version-link"
|
||||
to="[object Object]"
|
||||
|
@ -31,8 +40,14 @@ exports[`Design management design version dropdown component renders design vers
|
|||
class="fa fa-check pull-right"
|
||||
/>
|
||||
</router-link-stub>
|
||||
</gl-dropdown-item-stub>
|
||||
<gl-dropdown-item-stub>
|
||||
</gl-new-dropdown-item-stub>
|
||||
<gl-new-dropdown-item-stub
|
||||
avatarurl=""
|
||||
iconcolor=""
|
||||
iconname=""
|
||||
iconrightname=""
|
||||
secondarytext=""
|
||||
>
|
||||
<router-link-stub
|
||||
class="d-flex js-version-link"
|
||||
to="[object Object]"
|
||||
|
@ -51,19 +66,28 @@ exports[`Design management design version dropdown component renders design vers
|
|||
|
||||
<!---->
|
||||
</router-link-stub>
|
||||
</gl-dropdown-item-stub>
|
||||
</gl-dropdown-stub>
|
||||
</gl-new-dropdown-item-stub>
|
||||
</gl-new-dropdown-stub>
|
||||
`;
|
||||
|
||||
exports[`Design management design version dropdown component renders design version list 1`] = `
|
||||
<gl-dropdown-stub
|
||||
<gl-new-dropdown-stub
|
||||
category="tertiary"
|
||||
class="design-version-dropdown"
|
||||
headertext=""
|
||||
issueiid=""
|
||||
projectpath=""
|
||||
size="small"
|
||||
text="Showing Latest Version"
|
||||
variant="link"
|
||||
variant="default"
|
||||
>
|
||||
<gl-dropdown-item-stub>
|
||||
<gl-new-dropdown-item-stub
|
||||
avatarurl=""
|
||||
iconcolor=""
|
||||
iconname=""
|
||||
iconrightname=""
|
||||
secondarytext=""
|
||||
>
|
||||
<router-link-stub
|
||||
class="d-flex js-version-link"
|
||||
to="[object Object]"
|
||||
|
@ -86,8 +110,14 @@ exports[`Design management design version dropdown component renders design vers
|
|||
class="fa fa-check pull-right"
|
||||
/>
|
||||
</router-link-stub>
|
||||
</gl-dropdown-item-stub>
|
||||
<gl-dropdown-item-stub>
|
||||
</gl-new-dropdown-item-stub>
|
||||
<gl-new-dropdown-item-stub
|
||||
avatarurl=""
|
||||
iconcolor=""
|
||||
iconname=""
|
||||
iconrightname=""
|
||||
secondarytext=""
|
||||
>
|
||||
<router-link-stub
|
||||
class="d-flex js-version-link"
|
||||
to="[object Object]"
|
||||
|
@ -106,6 +136,6 @@ exports[`Design management design version dropdown component renders design vers
|
|||
|
||||
<!---->
|
||||
</router-link-stub>
|
||||
</gl-dropdown-item-stub>
|
||||
</gl-dropdown-stub>
|
||||
</gl-new-dropdown-item-stub>
|
||||
</gl-new-dropdown-stub>
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import DesignDropzone from '~/design_management_new/components/upload/design_dropzone.vue';
|
||||
import createFlash from '~/flash';
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
|
@ -12,10 +13,16 @@ describe('Design management dropzone component', () => {
|
|||
};
|
||||
|
||||
const findDropzoneCard = () => wrapper.find('.design-dropzone-card');
|
||||
const findDropzoneArea = () => wrapper.find('[data-testid="dropzone-area"]');
|
||||
const findIcon = () => wrapper.find(GlIcon);
|
||||
|
||||
function createComponent({ slots = {}, data = {} } = {}) {
|
||||
function createComponent({ slots = {}, data = {}, props = {} } = {}) {
|
||||
wrapper = shallowMount(DesignDropzone, {
|
||||
slots,
|
||||
propsData: {
|
||||
hasDesigns: true,
|
||||
...props,
|
||||
},
|
||||
data() {
|
||||
return data;
|
||||
},
|
||||
|
@ -129,4 +136,16 @@ describe('Design management dropzone component', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('applies correct classes when there are no designs or no design saving loader', () => {
|
||||
createComponent({ props: { hasDesigns: false } });
|
||||
expect(findDropzoneArea().classes()).not.toContain('gl-flex-direction-column');
|
||||
expect(findIcon().classes()).toEqual(['gl-mr-4']);
|
||||
});
|
||||
|
||||
it('applies correct classes when there are designs or design saving loader', () => {
|
||||
createComponent({ props: { hasDesigns: true } });
|
||||
expect(findDropzoneArea().classes()).toContain('gl-flex-direction-column');
|
||||
expect(findIcon().classes()).toEqual(['gl-mb-2']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import DesignVersionDropdown from '~/design_management_new/components/upload/design_version_dropdown.vue';
|
||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { GlNewDropdown, GlNewDropdownItem } from '@gitlab/ui';
|
||||
import mockAllVersions from './mock_data/all_versions';
|
||||
|
||||
const LATEST_VERSION_ID = 3;
|
||||
|
@ -75,7 +75,7 @@ describe('Design management design version dropdown component', () => {
|
|||
createComponent();
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
expect(wrapper.find(GlNewDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -83,7 +83,7 @@ describe('Design management design version dropdown component', () => {
|
|||
createComponent({ maxVersions: 1 });
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
expect(wrapper.find(GlNewDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -91,7 +91,7 @@ describe('Design management design version dropdown component', () => {
|
|||
createComponent({ $route: designRouteFactory(PREVIOUS_VERSION_ID) });
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.find(GlDropdown).attributes('text')).toBe(`Showing Version #1`);
|
||||
expect(wrapper.find(GlNewDropdown).attributes('text')).toBe(`Showing Version #1`);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -99,7 +99,7 @@ describe('Design management design version dropdown component', () => {
|
|||
createComponent({ $route: designRouteFactory(LATEST_VERSION_ID) });
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.find(GlDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
expect(wrapper.find(GlNewDropdown).attributes('text')).toBe('Showing Latest Version');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -107,7 +107,7 @@ describe('Design management design version dropdown component', () => {
|
|||
createComponent();
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.findAll(GlDropdownItem)).toHaveLength(wrapper.vm.allVersions.length);
|
||||
expect(wrapper.findAll(GlNewDropdownItem)).toHaveLength(wrapper.vm.allVersions.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`Design management index page designs does not render toolbar when there is no permission 1`] = `
|
||||
<div
|
||||
class="gl-mt-2"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
@ -12,18 +13,24 @@ exports[`Design management index page designs does not render toolbar when there
|
|||
<ol
|
||||
class="list-unstyled row"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="gl-flex-direction-column col-md-6 col-lg-3 gl-mb-3"
|
||||
data-testid="design-dropzone-wrapper"
|
||||
>
|
||||
<design-dropzone-stub
|
||||
class="design-list-item"
|
||||
class="design-list-item design-list-item-new"
|
||||
hasdesigns="true"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-1-name"
|
||||
|
@ -36,9 +43,11 @@ exports[`Design management index page designs does not render toolbar when there
|
|||
<!---->
|
||||
</li>
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-2-name"
|
||||
|
@ -51,9 +60,11 @@ exports[`Design management index page designs does not render toolbar when there
|
|||
<!---->
|
||||
</li>
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-3-name"
|
||||
|
@ -76,31 +87,44 @@ exports[`Design management index page designs does not render toolbar when there
|
|||
|
||||
exports[`Design management index page designs renders designs list and header with upload button 1`] = `
|
||||
<div
|
||||
class="gl-mt-2"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<header
|
||||
class="row-content-block border-top-0 p-2 d-flex"
|
||||
>
|
||||
<div
|
||||
class="d-flex justify-content-between align-items-center w-100"
|
||||
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full"
|
||||
>
|
||||
<design-version-dropdown-stub />
|
||||
<div>
|
||||
<span
|
||||
class="gl-font-weight-bold gl-mr-3"
|
||||
>
|
||||
Designs
|
||||
</span>
|
||||
|
||||
<design-version-dropdown-stub />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="qa-selector-toolbar d-flex"
|
||||
class="qa-selector-toolbar gl-display-flex"
|
||||
>
|
||||
<gl-deprecated-button-stub
|
||||
class="mr-2 js-select-all"
|
||||
size="md"
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
class="gl-mr-2 js-select-all"
|
||||
icon=""
|
||||
size="small"
|
||||
variant="link"
|
||||
>
|
||||
Select all
|
||||
</gl-deprecated-button-stub>
|
||||
|
||||
</gl-button-stub>
|
||||
|
||||
<div>
|
||||
<delete-button-stub
|
||||
buttonclass="btn-danger btn-inverted mr-2"
|
||||
buttonvariant=""
|
||||
buttonclass="gl-mr-4"
|
||||
buttonsize="small"
|
||||
buttonvariant="danger"
|
||||
>
|
||||
|
||||
Delete selected
|
||||
|
@ -120,18 +144,24 @@ exports[`Design management index page designs renders designs list and header wi
|
|||
<ol
|
||||
class="list-unstyled row"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="gl-flex-direction-column col-md-6 col-lg-3 gl-mb-3"
|
||||
data-testid="design-dropzone-wrapper"
|
||||
>
|
||||
<design-dropzone-stub
|
||||
class="design-list-item"
|
||||
class="design-list-item design-list-item-new"
|
||||
hasdesigns="true"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-1-name"
|
||||
|
@ -147,9 +177,11 @@ exports[`Design management index page designs renders designs list and header wi
|
|||
/>
|
||||
</li>
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-2-name"
|
||||
|
@ -165,9 +197,11 @@ exports[`Design management index page designs renders designs list and header wi
|
|||
/>
|
||||
</li>
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-md-6 col-lg-3 gl-mb-3"
|
||||
>
|
||||
<design-dropzone-stub>
|
||||
<design-dropzone-stub
|
||||
hasdesigns="true"
|
||||
>
|
||||
<design-stub
|
||||
event="NONE"
|
||||
filename="design-3-name"
|
||||
|
@ -193,6 +227,7 @@ exports[`Design management index page designs renders designs list and header wi
|
|||
|
||||
exports[`Design management index page designs renders error 1`] = `
|
||||
<div
|
||||
class="gl-mt-2"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
@ -223,6 +258,7 @@ exports[`Design management index page designs renders error 1`] = `
|
|||
|
||||
exports[`Design management index page designs renders loading icon 1`] = `
|
||||
<div
|
||||
class="gl-mt-2"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
@ -243,8 +279,9 @@ exports[`Design management index page designs renders loading icon 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`Design management index page when has no designs renders empty text 1`] = `
|
||||
exports[`Design management index page when has no designs renders design dropzone 1`] = `
|
||||
<div
|
||||
class="gl-mt-2"
|
||||
data-testid="designs-root"
|
||||
>
|
||||
<!---->
|
||||
|
@ -255,11 +292,18 @@ exports[`Design management index page when has no designs renders empty text 1`]
|
|||
<ol
|
||||
class="list-unstyled row"
|
||||
>
|
||||
<span
|
||||
class="gl-font-weight-bold gl-font-weight-bold gl-ml-5 gl-mb-4"
|
||||
>
|
||||
Designs
|
||||
</span>
|
||||
|
||||
<li
|
||||
class="col-md-6 col-lg-4 mb-3"
|
||||
class="col-12"
|
||||
data-testid="design-dropzone-wrapper"
|
||||
>
|
||||
<design-dropzone-stub
|
||||
class="design-list-item"
|
||||
class=""
|
||||
/>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ describe('Design management index page', () => {
|
|||
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
|
||||
const findDeleteButton = () => wrapper.find(DeleteButton);
|
||||
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
|
||||
const dropzoneClasses = () => findDropzone().classes();
|
||||
const findDropzoneWrapper = () => wrapper.find('[data-testid="design-dropzone-wrapper"]');
|
||||
const findFirstDropzoneWithDesign = () => wrapper.findAll(DesignDropzone).at(1);
|
||||
|
||||
function createComponent({
|
||||
|
@ -151,6 +153,22 @@ describe('Design management index page', () => {
|
|||
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('has correct classes applied to design dropzone', () => {
|
||||
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
|
||||
expect(dropzoneClasses()).toContain('design-list-item');
|
||||
expect(dropzoneClasses()).toContain('design-list-item-new');
|
||||
});
|
||||
|
||||
it('has correct classes applied to dropzone wrapper', () => {
|
||||
createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
|
||||
expect(findDropzoneWrapper().classes()).toEqual([
|
||||
'gl-flex-direction-column',
|
||||
'col-md-6',
|
||||
'col-lg-3',
|
||||
'gl-mb-3',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when has no designs', () => {
|
||||
|
@ -158,11 +176,20 @@ describe('Design management index page', () => {
|
|||
createComponent();
|
||||
});
|
||||
|
||||
it('renders empty text', () =>
|
||||
it('renders design dropzone', () =>
|
||||
wrapper.vm.$nextTick().then(() => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
}));
|
||||
|
||||
it('has correct classes applied to design dropzone', () => {
|
||||
expect(dropzoneClasses()).not.toContain('design-list-item');
|
||||
expect(dropzoneClasses()).not.toContain('design-list-item-new');
|
||||
});
|
||||
|
||||
it('has correct classes applied to dropzone wrapper', () => {
|
||||
expect(findDropzoneWrapper().classes()).toEqual(['col-12']);
|
||||
});
|
||||
|
||||
it('does not render a toolbar with buttons', () =>
|
||||
wrapper.vm.$nextTick().then(() => {
|
||||
expect(findToolbar().exists()).toBe(false);
|
||||
|
@ -227,12 +254,18 @@ describe('Design management index page', () => {
|
|||
},
|
||||
};
|
||||
|
||||
return wrapper.vm.$nextTick().then(() => {
|
||||
findDropzone().vm.$emit('change', [{ name: 'test' }]);
|
||||
expect(mutate).toHaveBeenCalledWith(mutationVariables);
|
||||
expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
|
||||
expect(wrapper.vm.isSaving).toBeTruthy();
|
||||
});
|
||||
return wrapper.vm
|
||||
.$nextTick()
|
||||
.then(() => {
|
||||
findDropzone().vm.$emit('change', [{ name: 'test' }]);
|
||||
expect(mutate).toHaveBeenCalledWith(mutationVariables);
|
||||
expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
|
||||
expect(wrapper.vm.isSaving).toBeTruthy();
|
||||
})
|
||||
.then(() => {
|
||||
expect(dropzoneClasses()).toContain('design-list-item');
|
||||
expect(dropzoneClasses()).toContain('design-list-item-new');
|
||||
});
|
||||
});
|
||||
|
||||
it('sets isSaving', () => {
|
||||
|
@ -380,8 +413,7 @@ describe('Design management index page', () => {
|
|||
|
||||
it('renders toolbar buttons', () => {
|
||||
expect(findToolbar().exists()).toBe(true);
|
||||
expect(findToolbar().classes()).toContain('d-flex');
|
||||
expect(findToolbar().classes()).not.toContain('d-none');
|
||||
expect(findToolbar().isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('adds two designs to selected designs when their checkboxes are checked', () => {
|
||||
|
@ -440,7 +472,7 @@ describe('Design management index page', () => {
|
|||
|
||||
it('on latest version when has no designs toolbar buttons are invisible', () => {
|
||||
createComponent({ designs: [], allVersions: [mockVersion] });
|
||||
expect(findToolbar().classes()).toContain('d-none');
|
||||
expect(findToolbar().isVisible()).toBe(false);
|
||||
});
|
||||
|
||||
describe('on non-latest version', () => {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Alert integration settings form default state should match the default snapshot 1`] = `
|
||||
<div>
|
||||
<p>
|
||||
<gl-sprintf-stub
|
||||
message="Action to take when receiving an alert. %{docsLink}"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<form>
|
||||
<gl-form-group-stub
|
||||
class="gl-pl-0"
|
||||
>
|
||||
<gl-form-checkbox-stub
|
||||
checked="true"
|
||||
data-qa-selector="create_issue_checkbox"
|
||||
>
|
||||
<span>
|
||||
Create an issue. Issues are created for each alert triggered.
|
||||
</span>
|
||||
</gl-form-checkbox-stub>
|
||||
</gl-form-group-stub>
|
||||
|
||||
<gl-form-group-stub
|
||||
class="col-8 col-md-9 gl-px-6"
|
||||
label-for="alert-integration-settings-issue-template"
|
||||
label-size="sm"
|
||||
>
|
||||
<label
|
||||
class="gl-display-inline-flex"
|
||||
for="alert-integration-settings-issue-template"
|
||||
>
|
||||
|
||||
Issue template (optional)
|
||||
|
||||
<gl-link-stub
|
||||
href="/help/user/project/description_templates#creating-issue-templates"
|
||||
target="_blank"
|
||||
>
|
||||
<gl-icon-stub
|
||||
name="question"
|
||||
size="12"
|
||||
/>
|
||||
</gl-link-stub>
|
||||
</label>
|
||||
|
||||
<gl-new-dropdown-stub
|
||||
block="true"
|
||||
category="tertiary"
|
||||
data-qa-selector="incident_templates_dropdown"
|
||||
headertext=""
|
||||
id="alert-integration-settings-issue-template"
|
||||
size="medium"
|
||||
text="selecte_tmpl"
|
||||
variant="default"
|
||||
>
|
||||
<gl-new-dropdown-item-stub
|
||||
avatarurl=""
|
||||
data-qa-selector="incident_templates_item"
|
||||
iconcolor=""
|
||||
iconname=""
|
||||
iconrightname=""
|
||||
ischeckitem="true"
|
||||
secondarytext=""
|
||||
>
|
||||
|
||||
No template selected
|
||||
|
||||
</gl-new-dropdown-item-stub>
|
||||
</gl-new-dropdown-stub>
|
||||
</gl-form-group-stub>
|
||||
|
||||
<gl-form-group-stub
|
||||
class="gl-pl-0 gl-mb-5"
|
||||
>
|
||||
<gl-form-checkbox-stub>
|
||||
<span>
|
||||
Send a separate email notification to Developers.
|
||||
</span>
|
||||
</gl-form-checkbox-stub>
|
||||
</gl-form-group-stub>
|
||||
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
class="js-no-auto-disable"
|
||||
data-qa-selector="save_changes_button"
|
||||
icon=""
|
||||
size="medium"
|
||||
type="submit"
|
||||
variant="success"
|
||||
>
|
||||
|
||||
Save changes
|
||||
|
||||
</gl-button-stub>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,56 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`IncidentsSettingTabs should render the component 1`] = `
|
||||
<section
|
||||
class="settings no-animate qa-incident-management-settings"
|
||||
data-qa-selector="incidents_settings_content"
|
||||
id="incident-management-settings"
|
||||
>
|
||||
<div
|
||||
class="settings-header"
|
||||
>
|
||||
<h3
|
||||
class="h4"
|
||||
>
|
||||
|
||||
Incidents
|
||||
|
||||
</h3>
|
||||
|
||||
<gl-button-stub
|
||||
category="tertiary"
|
||||
class="js-settings-toggle"
|
||||
icon=""
|
||||
size="medium"
|
||||
variant="default"
|
||||
>
|
||||
Expand
|
||||
</gl-button-stub>
|
||||
|
||||
<p>
|
||||
|
||||
Set up integrations with external tools to help better manage incidents.
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="settings-content"
|
||||
>
|
||||
<gl-tabs-stub
|
||||
theme="indigo"
|
||||
>
|
||||
<gl-tab-stub
|
||||
title="Alert integration"
|
||||
>
|
||||
<alertssettingsform-stub
|
||||
class="gl-pt-3"
|
||||
data-testid="AlertsSettingsForm-tab"
|
||||
/>
|
||||
</gl-tab-stub>
|
||||
<!---->
|
||||
<!---->
|
||||
</gl-tabs-stub>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
|
@ -0,0 +1,71 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import AlertsSettingsForm from '~/incidents_settings/components/alerts_form.vue';
|
||||
import { ERROR_MSG } from '~/incidents_settings/constants';
|
||||
import createFlash from '~/flash';
|
||||
import { refreshCurrentPage } from '~/lib/utils/url_utility';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
|
||||
jest.mock('~/flash');
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
||||
describe('Alert integration settings form', () => {
|
||||
let wrapper;
|
||||
|
||||
const findForm = () => wrapper.find({ ref: 'settingsForm' });
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(AlertsSettingsForm, {
|
||||
provide: {
|
||||
operationsSettingsEndpoint: 'operations/endpoint',
|
||||
alertSettings: {
|
||||
issueTemplateKey: 'selecte_tmpl',
|
||||
createIssue: true,
|
||||
sendEmail: false,
|
||||
templates: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
describe('default state', () => {
|
||||
it('should match the default snapshot', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('form', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mock.restore();
|
||||
});
|
||||
|
||||
it('should refresh the page on successful submit', () => {
|
||||
mock.onPatch().reply(200);
|
||||
findForm().trigger('submit');
|
||||
return waitForPromises().then(() => {
|
||||
expect(refreshCurrentPage).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a flah message on unsuccessful submit', () => {
|
||||
mock.onPatch().reply(400);
|
||||
findForm().trigger('submit');
|
||||
return waitForPromises().then(() => {
|
||||
expect(createFlash).toHaveBeenCalledWith(expect.stringContaining(ERROR_MSG), 'alert');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlTab } from '@gitlab/ui';
|
||||
import IncidentsSettingTabs from '~/incidents_settings/components/incidents_settings_tabs.vue';
|
||||
|
||||
describe('IncidentsSettingTabs', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallowMount(IncidentsSettingTabs);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const findToggleButton = () => wrapper.find({ ref: 'toggleBtn' });
|
||||
const findSectionHeader = () => wrapper.find({ ref: 'sectionHeader' });
|
||||
|
||||
const findIntegrationTabs = () => wrapper.findAll(GlTab);
|
||||
it('renders header text', () => {
|
||||
expect(findSectionHeader().text()).toBe('Incidents');
|
||||
});
|
||||
|
||||
describe('expand/collapse button', () => {
|
||||
it('renders as an expand button by default', () => {
|
||||
expect(findToggleButton().text()).toBe('Expand');
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the component', () => {
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render the tab for each active integration', () => {
|
||||
const activeTabs = wrapper.vm.$options.tabs.filter(tab => tab.active);
|
||||
expect(findIntegrationTabs().length).toBe(activeTabs.length);
|
||||
activeTabs.forEach((tab, index) => {
|
||||
expect(
|
||||
findIntegrationTabs()
|
||||
.at(index)
|
||||
.attributes('title'),
|
||||
).toBe(tab.title);
|
||||
expect(
|
||||
findIntegrationTabs()
|
||||
.at(index)
|
||||
.find(`[data-testid="${tab.component}-tab"]`)
|
||||
.exists(),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import SingleStatChart from '~/monitoring/components/charts/single_stat.vue';
|
||||
import { singleStatMetricsResult, singleStatMetricsWithFieldResult } from '../../mock_data';
|
||||
import { singleStatGraphData } from '../../graph_data';
|
||||
|
||||
describe('Single Stat Chart component', () => {
|
||||
let singleStatChart;
|
||||
|
@ -8,7 +8,7 @@ describe('Single Stat Chart component', () => {
|
|||
beforeEach(() => {
|
||||
singleStatChart = shallowMount(SingleStatChart, {
|
||||
propsData: {
|
||||
graphData: singleStatMetricsResult,
|
||||
graphData: singleStatGraphData({}, { unit: 'MB' }),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -20,15 +20,12 @@ describe('Single Stat Chart component', () => {
|
|||
describe('computed', () => {
|
||||
describe('statValue', () => {
|
||||
it('should interpolate the value and unit props', () => {
|
||||
expect(singleStatChart.vm.statValue).toBe('91.00MB');
|
||||
expect(singleStatChart.vm.statValue).toBe('1.00MB');
|
||||
});
|
||||
|
||||
it('should change the value representation to a percentile one', () => {
|
||||
singleStatChart.setProps({
|
||||
graphData: {
|
||||
...singleStatMetricsResult,
|
||||
maxValue: 120,
|
||||
},
|
||||
graphData: singleStatGraphData({ max_value: 120 }, { value: 91 }),
|
||||
});
|
||||
|
||||
expect(singleStatChart.vm.statValue).toContain('75.83%');
|
||||
|
@ -36,10 +33,7 @@ describe('Single Stat Chart component', () => {
|
|||
|
||||
it('should display NaN for non numeric maxValue values', () => {
|
||||
singleStatChart.setProps({
|
||||
graphData: {
|
||||
...singleStatMetricsResult,
|
||||
maxValue: 'not a number',
|
||||
},
|
||||
graphData: singleStatGraphData({ max_value: 'not a number' }),
|
||||
});
|
||||
|
||||
expect(singleStatChart.vm.statValue).toContain('NaN');
|
||||
|
@ -47,21 +41,7 @@ describe('Single Stat Chart component', () => {
|
|||
|
||||
it('should display NaN for missing query values', () => {
|
||||
singleStatChart.setProps({
|
||||
graphData: {
|
||||
...singleStatMetricsResult,
|
||||
metrics: [
|
||||
{
|
||||
...singleStatMetricsResult.metrics[0],
|
||||
result: [
|
||||
{
|
||||
...singleStatMetricsResult.metrics[0].result[0],
|
||||
value: [''],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
maxValue: 120,
|
||||
},
|
||||
graphData: singleStatGraphData({ max_value: 120 }, { value: 'NaN' }),
|
||||
});
|
||||
|
||||
expect(singleStatChart.vm.statValue).toContain('NaN');
|
||||
|
@ -70,7 +50,7 @@ describe('Single Stat Chart component', () => {
|
|||
describe('field attribute', () => {
|
||||
it('displays a label value instead of metric value when field attribute is used', () => {
|
||||
singleStatChart.setProps({
|
||||
graphData: singleStatMetricsWithFieldResult,
|
||||
graphData: singleStatGraphData({ field: 'job' }, { isVector: true }),
|
||||
});
|
||||
|
||||
return singleStatChart.vm.$nextTick(() => {
|
||||
|
@ -80,10 +60,7 @@ describe('Single Stat Chart component', () => {
|
|||
|
||||
it('displays No data to display if field attribute is not present', () => {
|
||||
singleStatChart.setProps({
|
||||
graphData: {
|
||||
...singleStatMetricsWithFieldResult,
|
||||
field: 'this-does-not-exist',
|
||||
},
|
||||
graphData: singleStatGraphData({ field: 'this-does-not-exist' }),
|
||||
});
|
||||
|
||||
return singleStatChart.vm.$nextTick(() => {
|
||||
|
|
|
@ -15,11 +15,11 @@ import {
|
|||
mockNamespace,
|
||||
mockNamespacedData,
|
||||
mockTimeRange,
|
||||
singleStatMetricsResult,
|
||||
graphDataPrometheusQueryRangeMultiTrack,
|
||||
barMockData,
|
||||
} from '../mock_data';
|
||||
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
|
||||
import { singleStatGraphData } from '../graph_data';
|
||||
|
||||
import { panelTypes } from '~/monitoring/constants';
|
||||
|
||||
|
@ -232,7 +232,7 @@ describe('Dashboard Panel', () => {
|
|||
data | component | hasCtxMenu
|
||||
${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
||||
${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
||||
${singleStatMetricsResult} | ${MonitorSingleStatChart} | ${true}
|
||||
${singleStatGraphData()} | ${MonitorSingleStatChart} | ${true}
|
||||
${anomalyMockGraphData} | ${MonitorAnomalyChart} | ${false}
|
||||
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
|
||||
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
|
||||
|
|
|
@ -3,10 +3,40 @@ import { panelTypes, metricStates } from '~/monitoring/constants';
|
|||
|
||||
const initTime = 1435781451.781;
|
||||
|
||||
const makeValue = val => [initTime, val];
|
||||
const makeValues = vals => vals.map((val, i) => [initTime + 15 * i, val]);
|
||||
|
||||
// Normalized Prometheus Responses
|
||||
|
||||
const scalarResult = ({ value = '1' } = {}) =>
|
||||
normalizeQueryResponseData({
|
||||
resultType: 'scalar',
|
||||
result: makeValue(value),
|
||||
});
|
||||
|
||||
const vectorResult = ({ value1 = '1', value2 = '2' } = {}) =>
|
||||
normalizeQueryResponseData({
|
||||
resultType: 'vector',
|
||||
result: [
|
||||
{
|
||||
metric: {
|
||||
__name__: 'up',
|
||||
job: 'prometheus',
|
||||
instance: 'localhost:9090',
|
||||
},
|
||||
value: makeValue(value1),
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: 'up',
|
||||
job: 'node',
|
||||
instance: 'localhost:9100',
|
||||
},
|
||||
value: makeValue(value2),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const matrixSingleResult = ({ values = ['1', '2', '3'] } = {}) =>
|
||||
normalizeQueryResponseData({
|
||||
resultType: 'matrix',
|
||||
|
@ -51,7 +81,6 @@ const matrixMultiResult = ({ values1 = ['1', '2', '3'], values2 = ['4', '5', '6'
|
|||
* @param {Object} dataOptions.metricCount
|
||||
* @param {Object} dataOptions.isMultiSeries
|
||||
*/
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const timeSeriesGraphData = (panelOptions = {}, dataOptions = {}) => {
|
||||
const { metricCount = 1, isMultiSeries = false } = dataOptions;
|
||||
|
||||
|
@ -68,3 +97,30 @@ export const timeSeriesGraphData = (panelOptions = {}, dataOptions = {}) => {
|
|||
...panelOptions,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate mock graph data according to options
|
||||
*
|
||||
* @param {Object} panelOptions - Panel options as in YML.
|
||||
* @param {Object} dataOptions
|
||||
* @param {Object} dataOptions.unit
|
||||
* @param {Object} dataOptions.value
|
||||
* @param {Object} dataOptions.isVector
|
||||
*/
|
||||
export const singleStatGraphData = (panelOptions = {}, dataOptions = {}) => {
|
||||
const { unit, value = '1', isVector = false } = dataOptions;
|
||||
|
||||
return mapPanelToViewModel({
|
||||
title: 'Single Stat Panel',
|
||||
type: panelTypes.SINGLE_STAT,
|
||||
metrics: [
|
||||
{
|
||||
label: 'Metric Label',
|
||||
state: metricStates.OK,
|
||||
result: isVector ? vectorResult({ value }) : scalarResult({ value }),
|
||||
unit,
|
||||
},
|
||||
],
|
||||
...panelOptions,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -334,36 +334,6 @@ export const metricsResult = [
|
|||
},
|
||||
];
|
||||
|
||||
export const singleStatMetricsResult = {
|
||||
title: 'Super Chart A2',
|
||||
type: 'single-stat',
|
||||
weight: 2,
|
||||
metrics: [
|
||||
{
|
||||
id: 'metric_a1',
|
||||
metricId: '2',
|
||||
query: 'max(go_memstats_alloc_bytes{job="prometheus"}) by (job) /1024/1024',
|
||||
unit: 'MB',
|
||||
label: 'Total Consumption',
|
||||
metric_id: 2,
|
||||
prometheus_endpoint_path:
|
||||
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
|
||||
result: [
|
||||
{
|
||||
metric: { job: 'prometheus' },
|
||||
value: ['2019-06-26T21:03:20.881Z', 91],
|
||||
values: [['2019-06-26T21:03:20.881Z', 91]],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const singleStatMetricsWithFieldResult = {
|
||||
...singleStatMetricsResult,
|
||||
field: 'job',
|
||||
};
|
||||
|
||||
export const graphDataPrometheusQueryRangeMultiTrack = {
|
||||
title: 'Super Chart A3',
|
||||
type: 'heatmap',
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import * as monitoringUtils from '~/monitoring/utils';
|
||||
import * as urlUtils from '~/lib/utils/url_utility';
|
||||
import { TEST_HOST } from 'jest/helpers/test_constants';
|
||||
import {
|
||||
mockProjectDir,
|
||||
singleStatMetricsResult,
|
||||
anomalyMockGraphData,
|
||||
barMockData,
|
||||
} from './mock_data';
|
||||
import { mockProjectDir, anomalyMockGraphData, barMockData } from './mock_data';
|
||||
import { metricsDashboardViewModel, graphData } from './fixture_data';
|
||||
import { singleStatGraphData } from './graph_data';
|
||||
|
||||
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
|
||||
|
||||
|
@ -82,7 +78,7 @@ describe('monitoring/utils', () => {
|
|||
it('validates data with the query format', () => {
|
||||
const validGraphData = monitoringUtils.graphDataValidatorForValues(
|
||||
true,
|
||||
singleStatMetricsResult,
|
||||
singleStatGraphData(),
|
||||
);
|
||||
|
||||
expect(validGraphData).toBe(true);
|
||||
|
@ -105,7 +101,7 @@ describe('monitoring/utils', () => {
|
|||
let threeMetrics;
|
||||
let fourMetrics;
|
||||
beforeEach(() => {
|
||||
oneMetric = singleStatMetricsResult;
|
||||
oneMetric = singleStatGraphData();
|
||||
threeMetrics = anomalyMockGraphData;
|
||||
|
||||
const metrics = [...threeMetrics.metrics];
|
||||
|
|
|
@ -26,6 +26,63 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
env.merge!(basic_auth_header(username, password))
|
||||
end
|
||||
|
||||
shared_examples 'find user from job token' do
|
||||
context 'when route is allowed to be authenticated' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: true } }
|
||||
|
||||
it "returns an Unauthorized exception for an invalid token" do
|
||||
set_token('invalid token')
|
||||
|
||||
expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
|
||||
end
|
||||
|
||||
it "return user if token is valid" do
|
||||
set_token(job.token)
|
||||
|
||||
expect(subject).to eq(user)
|
||||
expect(@current_authenticated_job).to eq job
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#find_user_from_bearer_token' do
|
||||
let(:job) { create(:ci_build, user: user) }
|
||||
|
||||
subject { find_user_from_bearer_token }
|
||||
|
||||
context 'when the token is passed as an oauth token' do
|
||||
def set_token(token)
|
||||
env['HTTP_AUTHORIZATION'] = "Bearer #{token}"
|
||||
end
|
||||
|
||||
context 'with a job token' do
|
||||
it_behaves_like 'find user from job token'
|
||||
end
|
||||
|
||||
context 'with oauth token' do
|
||||
let(:application) { Doorkeeper::Application.create!(name: 'MyApp', redirect_uri: 'https://app.com', owner: user) }
|
||||
let(:token) { Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'api').token }
|
||||
|
||||
before do
|
||||
set_token(token)
|
||||
end
|
||||
|
||||
it { is_expected.to eq user }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a personal access token' do
|
||||
let(:pat) { create(:personal_access_token, user: user) }
|
||||
let(:token) { pat.token }
|
||||
|
||||
before do
|
||||
env[described_class::PRIVATE_TOKEN_HEADER] = pat.token
|
||||
end
|
||||
|
||||
it { is_expected.to eq user }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#find_user_from_warden' do
|
||||
context 'with CSRF token' do
|
||||
before do
|
||||
|
@ -522,8 +579,24 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
end
|
||||
|
||||
describe '#validate_access_token!' do
|
||||
subject { validate_access_token! }
|
||||
|
||||
let(:personal_access_token) { create(:personal_access_token, user: user) }
|
||||
|
||||
context 'with a job token' do
|
||||
let(:route_authentication_setting) { { job_token_allowed: true } }
|
||||
let(:job) { create(:ci_build, user: user) }
|
||||
|
||||
before do
|
||||
env['HTTP_AUTHORIZATION'] = "Bearer #{job.token}"
|
||||
find_user_from_bearer_token
|
||||
end
|
||||
|
||||
it 'does not raise an error' do
|
||||
expect { subject }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns nil if no access_token present' do
|
||||
expect(validate_access_token!).to be_nil
|
||||
end
|
||||
|
|
|
@ -103,6 +103,12 @@ RSpec.describe Jira::Requests::Issues::ListService do
|
|||
subject
|
||||
end
|
||||
end
|
||||
|
||||
it 'requests for default fields' do
|
||||
expect(client).to receive(:get).with(include("fields=#{described_class::DEFAULT_FIELDS}")).and_return([])
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,7 +27,7 @@ RSpec.describe Spam::SpamVerdictService do
|
|||
|
||||
before do
|
||||
allow(service).to receive(:akismet_verdict).and_return(nil)
|
||||
allow(service).to receive(:spam_verdict_verdict).and_return(nil)
|
||||
allow(service).to receive(:external_verdict).and_return(nil)
|
||||
end
|
||||
|
||||
context 'if all services return nil' do
|
||||
|
@ -62,7 +62,7 @@ RSpec.describe Spam::SpamVerdictService do
|
|||
context 'and they are supported' do
|
||||
before do
|
||||
allow(service).to receive(:akismet_verdict).and_return(DISALLOW)
|
||||
allow(service).to receive(:spam_verdict).and_return(BLOCK_USER)
|
||||
allow(service).to receive(:external_verdict).and_return(BLOCK_USER)
|
||||
end
|
||||
|
||||
it 'renders the more restrictive verdict' do
|
||||
|
@ -73,7 +73,7 @@ RSpec.describe Spam::SpamVerdictService do
|
|||
context 'and one is supported' do
|
||||
before do
|
||||
allow(service).to receive(:akismet_verdict).and_return('nonsense')
|
||||
allow(service).to receive(:spam_verdict).and_return(BLOCK_USER)
|
||||
allow(service).to receive(:external_verdict).and_return(BLOCK_USER)
|
||||
end
|
||||
|
||||
it 'renders the more restrictive verdict' do
|
||||
|
@ -84,7 +84,7 @@ RSpec.describe Spam::SpamVerdictService do
|
|||
context 'and none are supported' do
|
||||
before do
|
||||
allow(service).to receive(:akismet_verdict).and_return('nonsense')
|
||||
allow(service).to receive(:spam_verdict).and_return('rubbish')
|
||||
allow(service).to receive(:external_verdict).and_return('rubbish')
|
||||
end
|
||||
|
||||
it 'renders the more restrictive verdict' do
|
||||
|
@ -149,8 +149,8 @@ RSpec.describe Spam::SpamVerdictService do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#spam_verdict' do
|
||||
subject { service.send(:spam_verdict) }
|
||||
describe '#external_verdict' do
|
||||
subject { service.send(:external_verdict) }
|
||||
|
||||
context 'if a Spam Check endpoint enabled and set to a URL' do
|
||||
let(:spam_check_body) { {} }
|
||||
|
|
|
@ -47,7 +47,7 @@ module SimpleCovEnv
|
|||
def configure_profile
|
||||
SimpleCov.configure do
|
||||
load_profile 'test_frameworks'
|
||||
track_files '{app,config,danger,db,haml_lint,lib,qa,rubocop,scripts,tooling}/**/*.rb'
|
||||
track_files '{app,config/initializers,config/initializers_before_autoloader,db/post_migrate,haml_lint,lib,rubocop,tooling}/**/*.rb'
|
||||
|
||||
add_filter '/vendor/ruby/'
|
||||
add_filter '/app/controllers/sherlock/'
|
||||
|
@ -73,8 +73,7 @@ module SimpleCovEnv
|
|||
add_group 'Initializers', %w[config/initializers config/initializers_before_autoloader] # Matches EE files as well
|
||||
add_group 'Migrations', %w[db/migrate db/optional_migrations db/post_migrate] # Matches EE files as well
|
||||
add_group 'Libraries', %w[/lib /ee/lib]
|
||||
add_group 'Tooling', %w[/danger /haml_lint /rubocop /scripts /tooling]
|
||||
add_group 'QA', '/qa'
|
||||
add_group 'Tooling', %w[/haml_lint /rubocop /tooling]
|
||||
|
||||
merge_timeout 365.days
|
||||
end
|
||||
|
|
|
@ -848,10 +848,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.151.0.tgz#099905295d33eb31033f4a48eb3652da2f686239"
|
||||
integrity sha512-2PTSM8CFhUjeTFKfcq6E/YwPpOVdSVWupf3NhKO/bz/cisSBS5P7aWxaXKIaxy28ySyBKEfKaAT6b4rXTwvVgg==
|
||||
|
||||
"@gitlab/ui@17.21.0":
|
||||
version "17.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.21.0.tgz#e881bac4540e3db29ee32e1dfd452677a445cd10"
|
||||
integrity sha512-Ijh3QPlB3Y10Sk0f0eZ/rgRIKHGSzAWZLugw9sb+ppcn9OPbb+2vk0ZgCcdIrfkrX3G8tD8q0Ndl3K1nrz6a5g==
|
||||
"@gitlab/ui@17.22.1":
|
||||
version "17.22.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.22.1.tgz#368578d04bb49011690911599c22a7d306f5fe99"
|
||||
integrity sha512-elcu2gdvt1Afz3GMrIBQR+eujlA6JetLn44T1UzPHUhlaodT/w+TIj0+uPIbPiD7Oz6uR/sYwBqlZXQdBcVv3Q==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
"@gitlab/vue-toasted" "^1.3.0"
|
||||
|
|
Loading…
Reference in a new issue