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-merge-request-title-update-caches: &if-merge-request-title-update-caches
|
||||||
if: '$CI_MERGE_REQUEST_TITLE =~ /UPDATE CACHE/'
|
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-security-merge-request: &if-security-merge-request
|
||||||
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
|
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
|
||||||
|
|
||||||
|
@ -440,22 +443,27 @@
|
||||||
.rails:rules:ee-and-foss-migration:
|
.rails:rules:ee-and-foss-migration:
|
||||||
rules:
|
rules:
|
||||||
- changes: *db-patterns
|
- changes: *db-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-and-foss-unit:
|
.rails:rules:ee-and-foss-unit:
|
||||||
rules:
|
rules:
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-and-foss-integration:
|
.rails:rules:ee-and-foss-integration:
|
||||||
rules:
|
rules:
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-and-foss-system:
|
.rails:rules:ee-and-foss-system:
|
||||||
rules:
|
rules:
|
||||||
- changes: *code-backstage-patterns
|
- changes: *code-backstage-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-and-foss-fast_spec_helper:
|
.rails:rules:ee-and-foss-fast_spec_helper:
|
||||||
rules:
|
rules:
|
||||||
- changes: ["config/**/*"]
|
- changes: ["config/**/*"]
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:default-refs-code-backstage-qa:
|
.rails:rules:default-refs-code-backstage-qa:
|
||||||
rules:
|
rules:
|
||||||
|
@ -467,24 +475,28 @@
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
- changes: *db-patterns
|
- changes: *db-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-only-unit:
|
.rails:rules:ee-only-unit:
|
||||||
rules:
|
rules:
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-only-integration:
|
.rails:rules:ee-only-integration:
|
||||||
rules:
|
rules:
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
- changes: *backend-patterns
|
- changes: *backend-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:ee-only-system:
|
.rails:rules:ee-only-system:
|
||||||
rules:
|
rules:
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
- changes: *code-backstage-patterns
|
- changes: *code-backstage-patterns
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:as-if-foss-migration:
|
.rails:rules:as-if-foss-migration:
|
||||||
rules:
|
rules:
|
||||||
|
@ -530,6 +542,7 @@
|
||||||
rules:
|
rules:
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
- <<: *if-merge-request
|
- <<: *if-merge-request
|
||||||
changes: *code-backstage-patterns
|
changes: *code-backstage-patterns
|
||||||
- <<: *if-master-refs
|
- <<: *if-master-refs
|
||||||
|
@ -556,6 +569,7 @@
|
||||||
- <<: *if-not-ee
|
- <<: *if-not-ee
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-master-schedule-2-hourly
|
- <<: *if-master-schedule-2-hourly
|
||||||
|
- <<: *if-merge-request-title-run-all-rspec
|
||||||
|
|
||||||
.rails:rules:master-schedule-nightly--code-backstage:
|
.rails:rules:master-schedule-nightly--code-backstage:
|
||||||
rules:
|
rules:
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlDeprecatedButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
|
||||||
import { uniqueId } from 'lodash';
|
import { uniqueId } from 'lodash';
|
||||||
|
import { s__ } from '~/locale';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DeleteButton',
|
name: 'DeleteButton',
|
||||||
components: {
|
components: {
|
||||||
GlDeprecatedButton,
|
GlButton,
|
||||||
GlModal,
|
GlModal,
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
|
@ -25,7 +26,12 @@ export default {
|
||||||
buttonVariant: {
|
buttonVariant: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: '',
|
default: 'info',
|
||||||
|
},
|
||||||
|
buttonSize: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'medium',
|
||||||
},
|
},
|
||||||
hasSelectedDesigns: {
|
hasSelectedDesigns: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -38,27 +44,38 @@ export default {
|
||||||
modalId: uniqueId('design-deletion-confirmation-'),
|
modalId: uniqueId('design-deletion-confirmation-'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
modal: {
|
||||||
|
title: s__('DesignManagement|Delete designs confirmation'),
|
||||||
|
actionPrimary: {
|
||||||
|
text: s__('Delete'),
|
||||||
|
attributes: { variant: 'danger' },
|
||||||
|
},
|
||||||
|
actionCancel: {
|
||||||
|
text: s__('Cancel'),
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="gl-display-flex gl-align-items-center gl-h-full">
|
||||||
<gl-modal
|
<gl-modal
|
||||||
:modal-id="modalId"
|
:modal-id="modalId"
|
||||||
:title="s__('DesignManagement|Delete designs confirmation')"
|
:title="$options.modal.title"
|
||||||
:ok-title="s__('DesignManagement|Delete')"
|
:action-primary="$options.modal.actionPrimary"
|
||||||
ok-variant="danger"
|
:action-cancel="$options.modal.actionCancel"
|
||||||
@ok="$emit('deleteSelectedDesigns')"
|
@ok="$emit('deleteSelectedDesigns')"
|
||||||
>
|
>
|
||||||
<p>{{ s__('DesignManagement|Are you sure you want to delete the selected designs?') }}</p>
|
<p>{{ s__('DesignManagement|Are you sure you want to delete the selected designs?') }}</p>
|
||||||
</gl-modal>
|
</gl-modal>
|
||||||
<gl-deprecated-button
|
<gl-button
|
||||||
v-gl-modal-directive="modalId"
|
v-gl-modal-directive="modalId"
|
||||||
:variant="buttonVariant"
|
:variant="buttonVariant"
|
||||||
:disabled="isDeleting || !hasSelectedDesigns"
|
:size="buttonSize"
|
||||||
:class="buttonClass"
|
:class="buttonClass"
|
||||||
|
:disabled="isDeleting || !hasSelectedDesigns"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</gl-deprecated-button>
|
</gl-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -127,7 +127,7 @@ export default {
|
||||||
params: { id: filename },
|
params: { id: filename },
|
||||||
query: $route.query,
|
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 class="card-body p-0 d-flex-center overflow-hidden position-relative">
|
||||||
<div v-if="icon.name" class="design-event position-absolute">
|
<div v-if="icon.name" class="design-event position-absolute">
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlDeprecatedButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
|
import { GlButton, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||||
import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
|
import { VALID_DESIGN_FILE_MIMETYPE } from '../../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
GlDeprecatedButton,
|
GlButton,
|
||||||
GlLoadingIcon,
|
GlLoadingIcon,
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
|
@ -30,7 +30,7 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<gl-deprecated-button
|
<gl-button
|
||||||
v-gl-tooltip.hover
|
v-gl-tooltip.hover
|
||||||
:title="
|
:title="
|
||||||
s__(
|
s__(
|
||||||
|
@ -39,11 +39,12 @@ export default {
|
||||||
"
|
"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
variant="success"
|
variant="success"
|
||||||
|
size="small"
|
||||||
@click="openFileUpload"
|
@click="openFileUpload"
|
||||||
>
|
>
|
||||||
{{ s__('DesignManagement|Upload designs') }}
|
{{ s__('DesignManagement|Upload designs') }}
|
||||||
<gl-loading-icon v-if="isSaving" inline class="ml-1" />
|
<gl-loading-icon v-if="isSaving" inline class="ml-1" />
|
||||||
</gl-deprecated-button>
|
</gl-button>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
ref="fileUpload"
|
ref="fileUpload"
|
||||||
|
|
|
@ -12,6 +12,12 @@ export default {
|
||||||
GlLink,
|
GlLink,
|
||||||
GlSprintf,
|
GlSprintf,
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
hasDesigns: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragCounter: 0,
|
dragCounter: 0,
|
||||||
|
@ -76,28 +82,29 @@ export default {
|
||||||
>
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<button
|
<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"
|
@click="openFileUpload"
|
||||||
>
|
>
|
||||||
<div class="d-flex-center flex-column text-center">
|
<div
|
||||||
<gl-icon name="doc-new" :size="48" class="mb-4" />
|
:class="{ 'gl-flex-direction-column': hasDesigns }"
|
||||||
<p>
|
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center"
|
||||||
<gl-sprintf
|
data-testid="dropzone-area"
|
||||||
:message="
|
>
|
||||||
__(
|
<gl-icon name="upload" :size="24" :class="hasDesigns ? 'gl-mb-2' : 'gl-mr-4'" />
|
||||||
'%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}.',
|
<gl-sprintf
|
||||||
)
|
:message="
|
||||||
"
|
__(
|
||||||
>
|
'%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}',
|
||||||
<template #lineOne="{ content }"
|
)
|
||||||
><span class="d-block">{{ content }}</span>
|
"
|
||||||
</template>
|
>
|
||||||
|
<template #content="{ content }">
|
||||||
<template #link="{ content }">
|
<span class="gl-font-weight-bold">{{ content }} </span>
|
||||||
<gl-link class="h-100 w-100" @click.stop="openFileUpload">{{ content }}</gl-link>
|
</template>
|
||||||
</template>
|
<template #link="{ content }">
|
||||||
</gl-sprintf>
|
<gl-link @click.stop="openFileUpload">{{ content }}</gl-link>
|
||||||
</p>
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</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"
|
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">
|
<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>{{
|
<span>{{
|
||||||
__(
|
__(
|
||||||
'You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico.',
|
'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>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isDragDataValid" class="mw-50 text-center">
|
<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>
|
<span>{{ __('Drop your designs to start your upload.') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
import { GlNewDropdown, GlNewDropdownItem } from '@gitlab/ui';
|
||||||
import { __, sprintf } from '~/locale';
|
import { __, sprintf } from '~/locale';
|
||||||
import allVersionsMixin from '../../mixins/all_versions';
|
import allVersionsMixin from '../../mixins/all_versions';
|
||||||
import { findVersionId } from '../../utils/design_management_utils';
|
import { findVersionId } from '../../utils/design_management_utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
GlDropdown,
|
GlNewDropdown,
|
||||||
GlDropdownItem,
|
GlNewDropdownItem,
|
||||||
},
|
},
|
||||||
mixins: [allVersionsMixin],
|
mixins: [allVersionsMixin],
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -50,8 +50,8 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<gl-dropdown :text="dropdownText" variant="link" class="design-version-dropdown">
|
<gl-new-dropdown :text="dropdownText" size="small" class="design-version-dropdown">
|
||||||
<gl-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
|
<gl-new-dropdown-item v-for="(version, index) in allVersions" :key="version.node.id">
|
||||||
<router-link
|
<router-link
|
||||||
class="d-flex js-version-link"
|
class="d-flex js-version-link"
|
||||||
:to="{ path: $route.path, query: { version: findVersionId(version.node.id) } }"
|
:to="{ path: $route.path, query: { version: findVersionId(version.node.id) } }"
|
||||||
|
@ -71,6 +71,6 @@ export default {
|
||||||
class="fa fa-check pull-right"
|
class="fa fa-check pull-right"
|
||||||
></i>
|
></i>
|
||||||
</router-link>
|
</router-link>
|
||||||
</gl-dropdown-item>
|
</gl-new-dropdown-item>
|
||||||
</gl-dropdown>
|
</gl-new-dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlLoadingIcon, GlDeprecatedButton, GlAlert } from '@gitlab/ui';
|
import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
|
||||||
import createFlash from '~/flash';
|
import createFlash from '~/flash';
|
||||||
import { s__, sprintf } from '~/locale';
|
import { s__, sprintf } from '~/locale';
|
||||||
import UploadButton from '../components/upload/button.vue';
|
import UploadButton from '../components/upload/button.vue';
|
||||||
|
@ -33,7 +33,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
GlLoadingIcon,
|
GlLoadingIcon,
|
||||||
GlAlert,
|
GlAlert,
|
||||||
GlDeprecatedButton,
|
GlButton,
|
||||||
UploadButton,
|
UploadButton,
|
||||||
Design,
|
Design,
|
||||||
DesignDestroyer,
|
DesignDestroyer,
|
||||||
|
@ -96,6 +96,14 @@ export default {
|
||||||
? s__('DesignManagement|Deselect all')
|
? s__('DesignManagement|Deselect all')
|
||||||
: s__('DesignManagement|Select 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() {
|
mounted() {
|
||||||
this.toggleOnPasteListener(this.$route.name);
|
this.toggleOnPasteListener(this.$route.name);
|
||||||
|
@ -259,18 +267,22 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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">
|
<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">
|
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full">
|
||||||
<design-version-dropdown />
|
<div>
|
||||||
<div :class="['qa-selector-toolbar', { 'd-flex': hasDesigns, 'd-none': !hasDesigns }]">
|
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
|
||||||
<gl-deprecated-button
|
<design-version-dropdown />
|
||||||
|
</div>
|
||||||
|
<div v-show="hasDesigns" class="qa-selector-toolbar gl-display-flex">
|
||||||
|
<gl-button
|
||||||
v-if="isLatestVersion"
|
v-if="isLatestVersion"
|
||||||
variant="link"
|
variant="link"
|
||||||
class="mr-2 js-select-all"
|
size="small"
|
||||||
|
class="gl-mr-2 js-select-all"
|
||||||
@click="toggleDesignsSelection"
|
@click="toggleDesignsSelection"
|
||||||
>{{ selectAllButtonText }}</gl-deprecated-button
|
>{{ selectAllButtonText }}
|
||||||
>
|
</gl-button>
|
||||||
<design-destroyer
|
<design-destroyer
|
||||||
#default="{ mutate, loading }"
|
#default="{ mutate, loading }"
|
||||||
:filenames="selectedDesigns"
|
:filenames="selectedDesigns"
|
||||||
|
@ -280,7 +292,9 @@ export default {
|
||||||
<delete-button
|
<delete-button
|
||||||
v-if="isLatestVersion"
|
v-if="isLatestVersion"
|
||||||
:is-deleting="loading"
|
: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"
|
:has-selected-designs="hasSelectedDesigns"
|
||||||
@deleteSelectedDesigns="mutate()"
|
@deleteSelectedDesigns="mutate()"
|
||||||
>
|
>
|
||||||
|
@ -298,11 +312,22 @@ export default {
|
||||||
{{ __('An error occurred while loading designs. Please try again.') }}
|
{{ __('An error occurred while loading designs. Please try again.') }}
|
||||||
</gl-alert>
|
</gl-alert>
|
||||||
<ol v-else class="list-unstyled row">
|
<ol v-else class="list-unstyled row">
|
||||||
<li class="col-md-6 col-lg-4 mb-3">
|
<span
|
||||||
<design-dropzone class="design-list-item" @change="onUploadDesign" />
|
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>
|
||||||
<li v-for="design in designs" :key="design.id" class="col-md-6 col-lg-4 mb-3">
|
<li v-for="design in designs" :key="design.id" class="col-md-6 col-lg-3 gl-mb-3">
|
||||||
<design-dropzone @change="onExistingDesignDropzoneChange($event, design.filename)"
|
<design-dropzone
|
||||||
|
:has-designs="hasDesigns"
|
||||||
|
@change="onExistingDesignDropzoneChange($event, design.filename)"
|
||||||
><design v-bind="design" :is-uploading="isDesignToBeSaved(design.filename)"
|
><design v-bind="design" :is-uploading="isDesignToBeSaved(design.filename)"
|
||||||
/></design-dropzone>
|
/></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 mountOperationSettings from '~/operation_settings';
|
||||||
import mountGrafanaIntegration from '~/grafana_integration';
|
import mountGrafanaIntegration from '~/grafana_integration';
|
||||||
import initSettingsPanels from '~/settings_panels';
|
import initSettingsPanels from '~/settings_panels';
|
||||||
|
import initIncidentsSettings from '~/incidents_settings';
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
initIncidentsSettings();
|
||||||
mountErrorTrackingForm();
|
mountErrorTrackingForm();
|
||||||
mountOperationSettings();
|
mountOperationSettings();
|
||||||
mountGrafanaIntegration();
|
mountGrafanaIntegration();
|
||||||
|
|
|
@ -17,3 +17,8 @@
|
||||||
height: 230px;
|
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;
|
cursor: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.frame,
|
|
||||||
.frame.click-to-comment,
|
.frame.click-to-comment,
|
||||||
.btn-transparent.image-diff-overlay-add-comment {
|
.btn-transparent.image-diff-overlay-add-comment {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -11,7 +11,9 @@ module Projects
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def valid_params
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ module Jira
|
||||||
extend ::Gitlab::Utils::Override
|
extend ::Gitlab::Utils::Override
|
||||||
|
|
||||||
PER_PAGE = 100
|
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 = {})
|
def initialize(jira_service, params = {})
|
||||||
super(jira_service, params)
|
super(jira_service, params)
|
||||||
|
@ -22,7 +25,7 @@ module Jira
|
||||||
|
|
||||||
override :url
|
override :url
|
||||||
def 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
|
end
|
||||||
|
|
||||||
override :build_service_response
|
override :build_service_response
|
||||||
|
|
|
@ -14,7 +14,7 @@ module Spam
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
external_spam_check_result = spam_verdict
|
external_spam_check_result = external_verdict
|
||||||
akismet_result = akismet_verdict
|
akismet_result = akismet_verdict
|
||||||
|
|
||||||
# filter out anything we don't recognise, including nils.
|
# filter out anything we don't recognise, including nils.
|
||||||
|
@ -38,7 +38,7 @@ module Spam
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def spam_verdict
|
def external_verdict
|
||||||
return unless Gitlab::CurrentSettings.spam_check_endpoint_enabled
|
return unless Gitlab::CurrentSettings.spam_check_endpoint_enabled
|
||||||
return if endpoint_url.blank?
|
return if endpoint_url.blank?
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,24 @@
|
||||||
- else
|
- else
|
||||||
.js-design-management{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
|
.js-design-management{ data: { project_path: @project.full_path, issue_iid: @issue.iid, issue_path: project_issue_path(@project, @issue) } }
|
||||||
- else
|
- else
|
||||||
.mt-4
|
- if Feature.enabled?(:design_management_moved, @project)
|
||||||
.row.empty-state
|
.row.empty-state.design-dropzone-border.gl-mt-5
|
||||||
.col-12
|
.text-content.center.gl-font-weight-bold
|
||||||
.text-content
|
- requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements')
|
||||||
%h4.center
|
- requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url }
|
||||||
= _('The one place for your designs')
|
- support_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: support_url }
|
||||||
%p.center
|
- link_end = '</a>'.html_safe
|
||||||
- requirements_link_url = help_page_path('user/project/issues/design_management', anchor: 'requirements')
|
= 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 }
|
||||||
- requirements_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: requirements_link_url }
|
- else
|
||||||
- support_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: support_url }
|
.mt-4
|
||||||
- link_end = '</a>'.html_safe
|
.row.empty-state
|
||||||
= 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 }
|
.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
|
- 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' } }
|
.js-incidents-settings{ data: { operations_settings_endpoint: project_settings_operations_path(@project),
|
||||||
.settings-header
|
templates: templates.to_json,
|
||||||
%h3{ :class => "h4" }= _('Incidents')
|
create_issue: setting.create_issue.to_s,
|
||||||
%button.btn.js-settings-toggle{ type: 'button' }
|
issue_template_key: setting.issue_template_key.to_s,
|
||||||
= _('Expand')
|
send_email: setting.send_email.to_s } }
|
||||||
%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' }
|
|
||||||
|
|
|
@ -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)
|
Consult [GitLab tests in the Continuous Integration (CI) context](testing_guide/ci.md)
|
||||||
for more information.
|
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
|
### Review app jobs
|
||||||
|
|
||||||
Consult the [Review Apps](testing_guide/review_apps.md) dedicated page for more information.
|
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.
|
> [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)
|
`License-Check` is an approval rule you can enable to allow an individual or group to approve a
|
||||||
must be created with the case-sensitive name `License-Check`. This approval group must be set
|
merge request that contains a `denied` license.
|
||||||
with the number of approvals required greater than zero.
|
|
||||||
|
|
||||||
Once this group is added to your project, the approval rule is enabled for all Merge Requests. To
|
You can enable `License-Check` one of two ways:
|
||||||
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)
|
- Create a [project approval rule](../project/merge_requests/merge_request_approvals.md#multiple-approval-rules-premium)
|
||||||
section.
|
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.
|
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.
|
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
|
## Use cases
|
||||||
|
|
||||||
|
@ -657,34 +657,39 @@ and the associated classifications for each.
|
||||||
|
|
||||||
Policies can be configured by maintainers of the project.
|
Policies can be configured by maintainers of the project.
|
||||||
|
|
||||||
![Edit Policy](img/policies_maintainer_edit_v13_0.png)
|
![Edit Policy](img/policies_maintainer_edit_v13_2.png)
|
||||||
![Add Policy](img/policies_maintainer_add_v13_0.png)
|
![Add Policy](img/policies_maintainer_add_v13_2.png)
|
||||||
|
|
||||||
Developers of the project can view the policies configured in a project.
|
Developers of the project can view the policies configured in a project.
|
||||||
|
|
||||||
![View Policies](img/policies_v13_0.png)
|
![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
|
`License-Check` is an approval rule you can enable to allow an approver, individual, or group to
|
||||||
pipeline ID that has a `license_scanning` job to see the Licenses tab with the listed
|
approve a merge request that contains a `denied` license.
|
||||||
licenses (if any).
|
|
||||||
|
|
||||||
![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
|
Any code changes cause the approvals required to reset.
|
||||||
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.
|
|
||||||
|
|
||||||
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
|
An approval is required when a license report:
|
||||||
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. -->
|
- 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
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ module API
|
||||||
|
|
||||||
# Helper Methods for Grape Endpoint
|
# Helper Methods for Grape Endpoint
|
||||||
module HelperMethods
|
module HelperMethods
|
||||||
prepend_if_ee('EE::API::APIGuard::HelperMethods') # rubocop: disable Cop/InjectEnterpriseEditionModule
|
|
||||||
include Gitlab::Auth::AuthFinders
|
include Gitlab::Auth::AuthFinders
|
||||||
|
|
||||||
def access_token
|
def access_token
|
||||||
|
@ -66,7 +65,7 @@ module API
|
||||||
|
|
||||||
def find_user_from_sources
|
def find_user_from_sources
|
||||||
deploy_token_from_request ||
|
deploy_token_from_request ||
|
||||||
find_user_from_access_token ||
|
find_user_from_bearer_token ||
|
||||||
find_user_from_job_token ||
|
find_user_from_job_token ||
|
||||||
find_user_from_warden
|
find_user_from_warden
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,6 +41,16 @@ module API
|
||||||
end
|
end
|
||||||
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
|
# rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||||
# We can't rewrite this with StrongMemoize because `sudo!` would
|
# We can't rewrite this with StrongMemoize because `sudo!` would
|
||||||
# actually write to `@current_user`, and `sudo?` would immediately
|
# actually write to `@current_user`, and `sudo?` would immediately
|
||||||
|
|
|
@ -54,6 +54,11 @@ module Gitlab
|
||||||
User.find_by_feed_token(token) || raise(UnauthorizedError)
|
User.find_by_feed_token(token) || raise(UnauthorizedError)
|
||||||
end
|
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
|
def find_user_from_job_token
|
||||||
return unless route_authentication_setting[:job_token_allowed]
|
return unless route_authentication_setting[:job_token_allowed]
|
||||||
return find_user_from_basic_auth_job if route_authentication_setting[:job_token_allowed] == :basic_auth
|
return find_user_from_basic_auth_job if route_authentication_setting[:job_token_allowed] == :basic_auth
|
||||||
|
@ -136,6 +141,9 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_access_token!(scopes: [])
|
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 early if we've already authenticated via a deploy token
|
||||||
return if @current_authenticated_deploy_token.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
return if @current_authenticated_deploy_token.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||||
|
|
||||||
|
@ -155,6 +163,20 @@ module Gitlab
|
||||||
|
|
||||||
private
|
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
|
def route_authentication_setting
|
||||||
return {} unless respond_to?(:route_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}."
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "%{cores} cores"
|
msgid "%{cores} cores"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1289,7 +1292,7 @@ msgstr ""
|
||||||
msgid "Account: %{account}"
|
msgid "Account: %{account}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Action to take when receiving an alert."
|
msgid "Action to take when receiving an alert. %{docsLink}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
|
@ -7958,6 +7961,9 @@ msgstr ""
|
||||||
msgid "DesignManagement|Deselect all"
|
msgid "DesignManagement|Deselect all"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DesignManagement|Designs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Discard comment"
|
msgid "DesignManagement|Discard comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -8000,7 +8006,7 @@ msgstr ""
|
||||||
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
|
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
|
||||||
msgstr ""
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "DesignManagement|Unresolve thread"
|
msgid "DesignManagement|Unresolve thread"
|
||||||
|
@ -12407,7 +12413,19 @@ msgstr ""
|
||||||
msgid "Incident Management Limits"
|
msgid "Incident Management Limits"
|
||||||
msgstr ""
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
|
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"
|
msgid "More information is available|here"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "More information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
|
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -15634,6 +15655,9 @@ msgstr ""
|
||||||
msgid "No template"
|
msgid "No template"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No template selected"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "No test coverage"
|
msgid "No test coverage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -25418,9 +25442,24 @@ msgstr ""
|
||||||
msgid "User was successfully updated."
|
msgid "User was successfully updated."
|
||||||
msgstr ""
|
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"
|
msgid "UserLists|Define a set of users to be used within feature flag strategies"
|
||||||
msgstr ""
|
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"
|
msgid "UserLists|There are no users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
"@babel/preset-env": "^7.10.1",
|
"@babel/preset-env": "^7.10.1",
|
||||||
"@gitlab/at.js": "1.5.5",
|
"@gitlab/at.js": "1.5.5",
|
||||||
"@gitlab/svgs": "1.151.0",
|
"@gitlab/svgs": "1.151.0",
|
||||||
"@gitlab/ui": "17.21.0",
|
"@gitlab/ui": "17.22.1",
|
||||||
"@gitlab/visual-review-tools": "1.6.1",
|
"@gitlab/visual-review-tools": "1.6.1",
|
||||||
"@rails/actioncable": "^6.0.3-1",
|
"@rails/actioncable": "^6.0.3-1",
|
||||||
"@sentry/browser": "^5.10.2",
|
"@sentry/browser": "^5.10.2",
|
||||||
|
|
|
@ -5,10 +5,11 @@ module QA
|
||||||
module Project
|
module Project
|
||||||
module Settings
|
module Settings
|
||||||
class Incidents < Page::Base
|
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 :create_issue_checkbox
|
||||||
element :incident_templates_dropdown
|
element :incident_templates_dropdown
|
||||||
element :save_changes_button
|
element :save_changes_button
|
||||||
|
element :incident_templates_item
|
||||||
end
|
end
|
||||||
|
|
||||||
def enable_issues_for_incidents
|
def enable_issues_for_incidents
|
||||||
|
@ -16,8 +17,9 @@ module QA
|
||||||
end
|
end
|
||||||
|
|
||||||
def select_issue_template(template)
|
def select_issue_template(template)
|
||||||
|
click_element(:incident_templates_dropdown)
|
||||||
within_element :incident_templates_dropdown do
|
within_element :incident_templates_dropdown do
|
||||||
find(:option, template).select_option
|
find_element(:incident_templates_item, text: template).click
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ module QA
|
||||||
class Operations < Page::Base
|
class Operations < Page::Base
|
||||||
include QA::Page::Settings::Common
|
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
|
element :incidents_settings_content
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,15 +45,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
||||||
|
|
||||||
it 'updates form values' do
|
it 'updates form values' do
|
||||||
check(create_issue)
|
check(create_issue)
|
||||||
template_select = find_field('Issue template')
|
|
||||||
template_select.find(:xpath, 'option[2]').select_option
|
|
||||||
uncheck(send_email)
|
uncheck(send_email)
|
||||||
|
|
||||||
save_form
|
save_form
|
||||||
click_expand_incident_management_button
|
click_expand_incident_management_button
|
||||||
|
|
||||||
expect(find_field(create_issue)).to be_checked
|
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
|
expect(find_field(send_email)).not_to be_checked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,7 +61,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_form
|
def save_form
|
||||||
page.within "#edit_project_#{project.id}" do
|
page.within ".qa-incident-management-settings" do
|
||||||
click_on 'Save changes'
|
click_on 'Save changes'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
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';
|
import BatchDeleteButton from '~/design_management_new/components/delete_button.vue';
|
||||||
|
|
||||||
describe('Batch delete button component', () => {
|
describe('Batch delete button component', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
const findButton = () => wrapper.find(GlDeprecatedButton);
|
const findButton = () => wrapper.find(GlButton);
|
||||||
const findModal = () => wrapper.find(GlModal);
|
const findModal = () => wrapper.find(GlModal);
|
||||||
|
|
||||||
function createComponent(isDeleting = false) {
|
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`] = `
|
exports[`Design management list item component with no notes renders item with correct status icon for creation event 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with no notes renders item with correct status icon for deletion event 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with no notes renders item with correct status icon for modification event 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with no notes renders item with no status icon for none event 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with no notes renders loading spinner when isUploading is true 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with notes renders item with multiple comments 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<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`] = `
|
exports[`Design management list item component with notes renders item with single comment 1`] = `
|
||||||
<router-link-stub
|
<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]"
|
to="[object Object]"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -50,6 +50,7 @@ exports[`Design management toolbar component renders design and updated data 1`]
|
||||||
|
|
||||||
<delete-button-stub
|
<delete-button-stub
|
||||||
buttonclass=""
|
buttonclass=""
|
||||||
|
buttonsize="medium"
|
||||||
buttonvariant="danger"
|
buttonvariant="danger"
|
||||||
hasselecteddesigns="true"
|
hasselecteddesigns="true"
|
||||||
>
|
>
|
||||||
|
|
|
@ -4,8 +4,10 @@ exports[`Design management upload button component renders inverted upload desig
|
||||||
<div
|
<div
|
||||||
isinverted="true"
|
isinverted="true"
|
||||||
>
|
>
|
||||||
<gl-deprecated-button-stub
|
<gl-button-stub
|
||||||
size="md"
|
category="tertiary"
|
||||||
|
icon=""
|
||||||
|
size="small"
|
||||||
title="Adding a design with the same filename replaces the file in a new version."
|
title="Adding a design with the same filename replaces the file in a new version."
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
|
@ -13,7 +15,7 @@ exports[`Design management upload button component renders inverted upload desig
|
||||||
Upload designs
|
Upload designs
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
</gl-deprecated-button-stub>
|
</gl-button-stub>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
accept="image/*"
|
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`] = `
|
exports[`Design management upload button component renders loading icon 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<gl-deprecated-button-stub
|
<gl-button-stub
|
||||||
|
category="tertiary"
|
||||||
disabled="true"
|
disabled="true"
|
||||||
size="md"
|
icon=""
|
||||||
|
size="small"
|
||||||
title="Adding a design with the same filename replaces the file in a new version."
|
title="Adding a design with the same filename replaces the file in a new version."
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
|
@ -43,7 +47,7 @@ exports[`Design management upload button component renders loading icon 1`] = `
|
||||||
label="Loading"
|
label="Loading"
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
</gl-deprecated-button-stub>
|
</gl-button-stub>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
accept="image/*"
|
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`] = `
|
exports[`Design management upload button component renders upload design button 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<gl-deprecated-button-stub
|
<gl-button-stub
|
||||||
size="md"
|
category="tertiary"
|
||||||
|
icon=""
|
||||||
|
size="small"
|
||||||
title="Adding a design with the same filename replaces the file in a new version."
|
title="Adding a design with the same filename replaces the file in a new version."
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
|
@ -66,7 +72,7 @@ exports[`Design management upload button component renders upload design button
|
||||||
Upload designs
|
Upload designs
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
</gl-deprecated-button-stub>
|
</gl-button-stub>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
|
|
|
@ -5,22 +5,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -43,7 +42,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -56,7 +57,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style=""
|
style=""
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -74,22 +77,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -112,7 +114,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -125,7 +129,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style=""
|
style=""
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -143,22 +149,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -180,7 +185,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
<div
|
<div
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -193,7 +200,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -211,22 +220,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -248,7 +256,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
<div
|
<div
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -261,7 +271,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -279,22 +291,21 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -316,7 +327,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
<div
|
<div
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -329,7 +342,9 @@ exports[`Design management dropzone component when dragging renders correct temp
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -347,22 +362,21 @@ exports[`Design management dropzone component when no slot provided renders defa
|
||||||
class="w-100 position-relative"
|
class="w-100 position-relative"
|
||||||
>
|
>
|
||||||
<button
|
<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
|
<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
|
<gl-icon-stub
|
||||||
class="mb-4"
|
class="gl-mb-2"
|
||||||
name="doc-new"
|
name="upload"
|
||||||
size="48"
|
size="24"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>
|
<gl-sprintf-stub
|
||||||
<gl-sprintf-stub
|
message="%{contentStart}Drop files to attach, or %{contentEnd}%{linkStart}browse%{linkEnd}"
|
||||||
message="%{lineOneStart}Drag and drop to upload your designs%{lineOneEnd} or %{linkStart}click to upload%{linkEnd}."
|
/>
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -384,7 +398,9 @@ exports[`Design management dropzone component when no slot provided renders defa
|
||||||
<div
|
<div
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -397,7 +413,9 @@ exports[`Design management dropzone component when no slot provided renders defa
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -428,7 +446,9 @@ exports[`Design management dropzone component when slot provided renders dropzon
|
||||||
<div
|
<div
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Oh no!
|
Oh no!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
@ -441,7 +461,9 @@ exports[`Design management dropzone component when slot provided renders dropzon
|
||||||
class="mw-50 text-center"
|
class="mw-50 text-center"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3
|
||||||
|
class=""
|
||||||
|
>
|
||||||
Incoming!
|
Incoming!
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Design management design version dropdown component renders design version dropdown button 1`] = `
|
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"
|
class="design-version-dropdown"
|
||||||
|
headertext=""
|
||||||
issueiid=""
|
issueiid=""
|
||||||
projectpath=""
|
projectpath=""
|
||||||
|
size="small"
|
||||||
text="Showing Latest Version"
|
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
|
<router-link-stub
|
||||||
class="d-flex js-version-link"
|
class="d-flex js-version-link"
|
||||||
to="[object Object]"
|
to="[object Object]"
|
||||||
|
@ -31,8 +40,14 @@ exports[`Design management design version dropdown component renders design vers
|
||||||
class="fa fa-check pull-right"
|
class="fa fa-check pull-right"
|
||||||
/>
|
/>
|
||||||
</router-link-stub>
|
</router-link-stub>
|
||||||
</gl-dropdown-item-stub>
|
</gl-new-dropdown-item-stub>
|
||||||
<gl-dropdown-item-stub>
|
<gl-new-dropdown-item-stub
|
||||||
|
avatarurl=""
|
||||||
|
iconcolor=""
|
||||||
|
iconname=""
|
||||||
|
iconrightname=""
|
||||||
|
secondarytext=""
|
||||||
|
>
|
||||||
<router-link-stub
|
<router-link-stub
|
||||||
class="d-flex js-version-link"
|
class="d-flex js-version-link"
|
||||||
to="[object Object]"
|
to="[object Object]"
|
||||||
|
@ -51,19 +66,28 @@ exports[`Design management design version dropdown component renders design vers
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
</router-link-stub>
|
</router-link-stub>
|
||||||
</gl-dropdown-item-stub>
|
</gl-new-dropdown-item-stub>
|
||||||
</gl-dropdown-stub>
|
</gl-new-dropdown-stub>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Design management design version dropdown component renders design version list 1`] = `
|
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"
|
class="design-version-dropdown"
|
||||||
|
headertext=""
|
||||||
issueiid=""
|
issueiid=""
|
||||||
projectpath=""
|
projectpath=""
|
||||||
|
size="small"
|
||||||
text="Showing Latest Version"
|
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
|
<router-link-stub
|
||||||
class="d-flex js-version-link"
|
class="d-flex js-version-link"
|
||||||
to="[object Object]"
|
to="[object Object]"
|
||||||
|
@ -86,8 +110,14 @@ exports[`Design management design version dropdown component renders design vers
|
||||||
class="fa fa-check pull-right"
|
class="fa fa-check pull-right"
|
||||||
/>
|
/>
|
||||||
</router-link-stub>
|
</router-link-stub>
|
||||||
</gl-dropdown-item-stub>
|
</gl-new-dropdown-item-stub>
|
||||||
<gl-dropdown-item-stub>
|
<gl-new-dropdown-item-stub
|
||||||
|
avatarurl=""
|
||||||
|
iconcolor=""
|
||||||
|
iconname=""
|
||||||
|
iconrightname=""
|
||||||
|
secondarytext=""
|
||||||
|
>
|
||||||
<router-link-stub
|
<router-link-stub
|
||||||
class="d-flex js-version-link"
|
class="d-flex js-version-link"
|
||||||
to="[object Object]"
|
to="[object Object]"
|
||||||
|
@ -106,6 +136,6 @@ exports[`Design management design version dropdown component renders design vers
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
</router-link-stub>
|
</router-link-stub>
|
||||||
</gl-dropdown-item-stub>
|
</gl-new-dropdown-item-stub>
|
||||||
</gl-dropdown-stub>
|
</gl-new-dropdown-stub>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import DesignDropzone from '~/design_management_new/components/upload/design_dropzone.vue';
|
import DesignDropzone from '~/design_management_new/components/upload/design_dropzone.vue';
|
||||||
import createFlash from '~/flash';
|
import createFlash from '~/flash';
|
||||||
|
import { GlIcon } from '@gitlab/ui';
|
||||||
|
|
||||||
jest.mock('~/flash');
|
jest.mock('~/flash');
|
||||||
|
|
||||||
|
@ -12,10 +13,16 @@ describe('Design management dropzone component', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const findDropzoneCard = () => wrapper.find('.design-dropzone-card');
|
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, {
|
wrapper = shallowMount(DesignDropzone, {
|
||||||
slots,
|
slots,
|
||||||
|
propsData: {
|
||||||
|
hasDesigns: true,
|
||||||
|
...props,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return 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 { shallowMount } from '@vue/test-utils';
|
||||||
import DesignVersionDropdown from '~/design_management_new/components/upload/design_version_dropdown.vue';
|
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';
|
import mockAllVersions from './mock_data/all_versions';
|
||||||
|
|
||||||
const LATEST_VERSION_ID = 3;
|
const LATEST_VERSION_ID = 3;
|
||||||
|
@ -75,7 +75,7 @@ describe('Design management design version dropdown component', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
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 });
|
createComponent({ maxVersions: 1 });
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
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) });
|
createComponent({ $route: designRouteFactory(PREVIOUS_VERSION_ID) });
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
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) });
|
createComponent({ $route: designRouteFactory(LATEST_VERSION_ID) });
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
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();
|
createComponent();
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
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`] = `
|
exports[`Design management index page designs does not render toolbar when there is no permission 1`] = `
|
||||||
<div
|
<div
|
||||||
|
class="gl-mt-2"
|
||||||
data-testid="designs-root"
|
data-testid="designs-root"
|
||||||
>
|
>
|
||||||
<!---->
|
<!---->
|
||||||
|
@ -12,18 +13,24 @@ exports[`Design management index page designs does not render toolbar when there
|
||||||
<ol
|
<ol
|
||||||
class="list-unstyled row"
|
class="list-unstyled row"
|
||||||
>
|
>
|
||||||
|
<!---->
|
||||||
|
|
||||||
<li
|
<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
|
<design-dropzone-stub
|
||||||
class="design-list-item"
|
class="design-list-item design-list-item-new"
|
||||||
|
hasdesigns="true"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-1-name"
|
filename="design-1-name"
|
||||||
|
@ -36,9 +43,11 @@ exports[`Design management index page designs does not render toolbar when there
|
||||||
<!---->
|
<!---->
|
||||||
</li>
|
</li>
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-2-name"
|
filename="design-2-name"
|
||||||
|
@ -51,9 +60,11 @@ exports[`Design management index page designs does not render toolbar when there
|
||||||
<!---->
|
<!---->
|
||||||
</li>
|
</li>
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-3-name"
|
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`] = `
|
exports[`Design management index page designs renders designs list and header with upload button 1`] = `
|
||||||
<div
|
<div
|
||||||
|
class="gl-mt-2"
|
||||||
data-testid="designs-root"
|
data-testid="designs-root"
|
||||||
>
|
>
|
||||||
<header
|
<header
|
||||||
class="row-content-block border-top-0 p-2 d-flex"
|
class="row-content-block border-top-0 p-2 d-flex"
|
||||||
>
|
>
|
||||||
<div
|
<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
|
<div
|
||||||
class="qa-selector-toolbar d-flex"
|
class="qa-selector-toolbar gl-display-flex"
|
||||||
>
|
>
|
||||||
<gl-deprecated-button-stub
|
<gl-button-stub
|
||||||
class="mr-2 js-select-all"
|
category="tertiary"
|
||||||
size="md"
|
class="gl-mr-2 js-select-all"
|
||||||
|
icon=""
|
||||||
|
size="small"
|
||||||
variant="link"
|
variant="link"
|
||||||
>
|
>
|
||||||
Select all
|
Select all
|
||||||
</gl-deprecated-button-stub>
|
|
||||||
|
</gl-button-stub>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<delete-button-stub
|
<delete-button-stub
|
||||||
buttonclass="btn-danger btn-inverted mr-2"
|
buttonclass="gl-mr-4"
|
||||||
buttonvariant=""
|
buttonsize="small"
|
||||||
|
buttonvariant="danger"
|
||||||
>
|
>
|
||||||
|
|
||||||
Delete selected
|
Delete selected
|
||||||
|
@ -120,18 +144,24 @@ exports[`Design management index page designs renders designs list and header wi
|
||||||
<ol
|
<ol
|
||||||
class="list-unstyled row"
|
class="list-unstyled row"
|
||||||
>
|
>
|
||||||
|
<!---->
|
||||||
|
|
||||||
<li
|
<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
|
<design-dropzone-stub
|
||||||
class="design-list-item"
|
class="design-list-item design-list-item-new"
|
||||||
|
hasdesigns="true"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-1-name"
|
filename="design-1-name"
|
||||||
|
@ -147,9 +177,11 @@ exports[`Design management index page designs renders designs list and header wi
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-2-name"
|
filename="design-2-name"
|
||||||
|
@ -165,9 +197,11 @@ exports[`Design management index page designs renders designs list and header wi
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<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
|
<design-stub
|
||||||
event="NONE"
|
event="NONE"
|
||||||
filename="design-3-name"
|
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`] = `
|
exports[`Design management index page designs renders error 1`] = `
|
||||||
<div
|
<div
|
||||||
|
class="gl-mt-2"
|
||||||
data-testid="designs-root"
|
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`] = `
|
exports[`Design management index page designs renders loading icon 1`] = `
|
||||||
<div
|
<div
|
||||||
|
class="gl-mt-2"
|
||||||
data-testid="designs-root"
|
data-testid="designs-root"
|
||||||
>
|
>
|
||||||
<!---->
|
<!---->
|
||||||
|
@ -243,8 +279,9 @@ exports[`Design management index page designs renders loading icon 1`] = `
|
||||||
</div>
|
</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
|
<div
|
||||||
|
class="gl-mt-2"
|
||||||
data-testid="designs-root"
|
data-testid="designs-root"
|
||||||
>
|
>
|
||||||
<!---->
|
<!---->
|
||||||
|
@ -255,11 +292,18 @@ exports[`Design management index page when has no designs renders empty text 1`]
|
||||||
<ol
|
<ol
|
||||||
class="list-unstyled row"
|
class="list-unstyled row"
|
||||||
>
|
>
|
||||||
|
<span
|
||||||
|
class="gl-font-weight-bold gl-font-weight-bold gl-ml-5 gl-mb-4"
|
||||||
|
>
|
||||||
|
Designs
|
||||||
|
</span>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
class="col-md-6 col-lg-4 mb-3"
|
class="col-12"
|
||||||
|
data-testid="design-dropzone-wrapper"
|
||||||
>
|
>
|
||||||
<design-dropzone-stub
|
<design-dropzone-stub
|
||||||
class="design-list-item"
|
class=""
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ describe('Design management index page', () => {
|
||||||
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
|
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
|
||||||
const findDeleteButton = () => wrapper.find(DeleteButton);
|
const findDeleteButton = () => wrapper.find(DeleteButton);
|
||||||
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
|
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);
|
const findFirstDropzoneWithDesign = () => wrapper.findAll(DesignDropzone).at(1);
|
||||||
|
|
||||||
function createComponent({
|
function createComponent({
|
||||||
|
@ -151,6 +153,22 @@ describe('Design management index page', () => {
|
||||||
|
|
||||||
expect(wrapper.element).toMatchSnapshot();
|
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', () => {
|
describe('when has no designs', () => {
|
||||||
|
@ -158,11 +176,20 @@ describe('Design management index page', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders empty text', () =>
|
it('renders design dropzone', () =>
|
||||||
wrapper.vm.$nextTick().then(() => {
|
wrapper.vm.$nextTick().then(() => {
|
||||||
expect(wrapper.element).toMatchSnapshot();
|
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', () =>
|
it('does not render a toolbar with buttons', () =>
|
||||||
wrapper.vm.$nextTick().then(() => {
|
wrapper.vm.$nextTick().then(() => {
|
||||||
expect(findToolbar().exists()).toBe(false);
|
expect(findToolbar().exists()).toBe(false);
|
||||||
|
@ -227,12 +254,18 @@ describe('Design management index page', () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return wrapper.vm.$nextTick().then(() => {
|
return wrapper.vm
|
||||||
findDropzone().vm.$emit('change', [{ name: 'test' }]);
|
.$nextTick()
|
||||||
expect(mutate).toHaveBeenCalledWith(mutationVariables);
|
.then(() => {
|
||||||
expect(wrapper.vm.filesToBeSaved).toEqual([{ name: 'test' }]);
|
findDropzone().vm.$emit('change', [{ name: 'test' }]);
|
||||||
expect(wrapper.vm.isSaving).toBeTruthy();
|
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', () => {
|
it('sets isSaving', () => {
|
||||||
|
@ -380,8 +413,7 @@ describe('Design management index page', () => {
|
||||||
|
|
||||||
it('renders toolbar buttons', () => {
|
it('renders toolbar buttons', () => {
|
||||||
expect(findToolbar().exists()).toBe(true);
|
expect(findToolbar().exists()).toBe(true);
|
||||||
expect(findToolbar().classes()).toContain('d-flex');
|
expect(findToolbar().isVisible()).toBe(true);
|
||||||
expect(findToolbar().classes()).not.toContain('d-none');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds two designs to selected designs when their checkboxes are checked', () => {
|
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', () => {
|
it('on latest version when has no designs toolbar buttons are invisible', () => {
|
||||||
createComponent({ designs: [], allVersions: [mockVersion] });
|
createComponent({ designs: [], allVersions: [mockVersion] });
|
||||||
expect(findToolbar().classes()).toContain('d-none');
|
expect(findToolbar().isVisible()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('on non-latest version', () => {
|
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 { shallowMount } from '@vue/test-utils';
|
||||||
import SingleStatChart from '~/monitoring/components/charts/single_stat.vue';
|
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', () => {
|
describe('Single Stat Chart component', () => {
|
||||||
let singleStatChart;
|
let singleStatChart;
|
||||||
|
@ -8,7 +8,7 @@ describe('Single Stat Chart component', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
singleStatChart = shallowMount(SingleStatChart, {
|
singleStatChart = shallowMount(SingleStatChart, {
|
||||||
propsData: {
|
propsData: {
|
||||||
graphData: singleStatMetricsResult,
|
graphData: singleStatGraphData({}, { unit: 'MB' }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,15 +20,12 @@ describe('Single Stat Chart component', () => {
|
||||||
describe('computed', () => {
|
describe('computed', () => {
|
||||||
describe('statValue', () => {
|
describe('statValue', () => {
|
||||||
it('should interpolate the value and unit props', () => {
|
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', () => {
|
it('should change the value representation to a percentile one', () => {
|
||||||
singleStatChart.setProps({
|
singleStatChart.setProps({
|
||||||
graphData: {
|
graphData: singleStatGraphData({ max_value: 120 }, { value: 91 }),
|
||||||
...singleStatMetricsResult,
|
|
||||||
maxValue: 120,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(singleStatChart.vm.statValue).toContain('75.83%');
|
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', () => {
|
it('should display NaN for non numeric maxValue values', () => {
|
||||||
singleStatChart.setProps({
|
singleStatChart.setProps({
|
||||||
graphData: {
|
graphData: singleStatGraphData({ max_value: 'not a number' }),
|
||||||
...singleStatMetricsResult,
|
|
||||||
maxValue: 'not a number',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(singleStatChart.vm.statValue).toContain('NaN');
|
expect(singleStatChart.vm.statValue).toContain('NaN');
|
||||||
|
@ -47,21 +41,7 @@ describe('Single Stat Chart component', () => {
|
||||||
|
|
||||||
it('should display NaN for missing query values', () => {
|
it('should display NaN for missing query values', () => {
|
||||||
singleStatChart.setProps({
|
singleStatChart.setProps({
|
||||||
graphData: {
|
graphData: singleStatGraphData({ max_value: 120 }, { value: 'NaN' }),
|
||||||
...singleStatMetricsResult,
|
|
||||||
metrics: [
|
|
||||||
{
|
|
||||||
...singleStatMetricsResult.metrics[0],
|
|
||||||
result: [
|
|
||||||
{
|
|
||||||
...singleStatMetricsResult.metrics[0].result[0],
|
|
||||||
value: [''],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
maxValue: 120,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(singleStatChart.vm.statValue).toContain('NaN');
|
expect(singleStatChart.vm.statValue).toContain('NaN');
|
||||||
|
@ -70,7 +50,7 @@ describe('Single Stat Chart component', () => {
|
||||||
describe('field attribute', () => {
|
describe('field attribute', () => {
|
||||||
it('displays a label value instead of metric value when field attribute is used', () => {
|
it('displays a label value instead of metric value when field attribute is used', () => {
|
||||||
singleStatChart.setProps({
|
singleStatChart.setProps({
|
||||||
graphData: singleStatMetricsWithFieldResult,
|
graphData: singleStatGraphData({ field: 'job' }, { isVector: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
return singleStatChart.vm.$nextTick(() => {
|
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', () => {
|
it('displays No data to display if field attribute is not present', () => {
|
||||||
singleStatChart.setProps({
|
singleStatChart.setProps({
|
||||||
graphData: {
|
graphData: singleStatGraphData({ field: 'this-does-not-exist' }),
|
||||||
...singleStatMetricsWithFieldResult,
|
|
||||||
field: 'this-does-not-exist',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return singleStatChart.vm.$nextTick(() => {
|
return singleStatChart.vm.$nextTick(() => {
|
||||||
|
|
|
@ -15,11 +15,11 @@ import {
|
||||||
mockNamespace,
|
mockNamespace,
|
||||||
mockNamespacedData,
|
mockNamespacedData,
|
||||||
mockTimeRange,
|
mockTimeRange,
|
||||||
singleStatMetricsResult,
|
|
||||||
graphDataPrometheusQueryRangeMultiTrack,
|
graphDataPrometheusQueryRangeMultiTrack,
|
||||||
barMockData,
|
barMockData,
|
||||||
} from '../mock_data';
|
} from '../mock_data';
|
||||||
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
|
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
|
||||||
|
import { singleStatGraphData } from '../graph_data';
|
||||||
|
|
||||||
import { panelTypes } from '~/monitoring/constants';
|
import { panelTypes } from '~/monitoring/constants';
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ describe('Dashboard Panel', () => {
|
||||||
data | component | hasCtxMenu
|
data | component | hasCtxMenu
|
||||||
${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
${dataWithType(panelTypes.AREA_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
||||||
${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
${dataWithType(panelTypes.LINE_CHART)} | ${MonitorTimeSeriesChart} | ${true}
|
||||||
${singleStatMetricsResult} | ${MonitorSingleStatChart} | ${true}
|
${singleStatGraphData()} | ${MonitorSingleStatChart} | ${true}
|
||||||
${anomalyMockGraphData} | ${MonitorAnomalyChart} | ${false}
|
${anomalyMockGraphData} | ${MonitorAnomalyChart} | ${false}
|
||||||
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
|
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
|
||||||
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
|
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
|
||||||
|
|
|
@ -3,10 +3,40 @@ import { panelTypes, metricStates } from '~/monitoring/constants';
|
||||||
|
|
||||||
const initTime = 1435781451.781;
|
const initTime = 1435781451.781;
|
||||||
|
|
||||||
|
const makeValue = val => [initTime, val];
|
||||||
const makeValues = vals => vals.map((val, i) => [initTime + 15 * i, val]);
|
const makeValues = vals => vals.map((val, i) => [initTime + 15 * i, val]);
|
||||||
|
|
||||||
// Normalized Prometheus Responses
|
// 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'] } = {}) =>
|
const matrixSingleResult = ({ values = ['1', '2', '3'] } = {}) =>
|
||||||
normalizeQueryResponseData({
|
normalizeQueryResponseData({
|
||||||
resultType: 'matrix',
|
resultType: 'matrix',
|
||||||
|
@ -51,7 +81,6 @@ const matrixMultiResult = ({ values1 = ['1', '2', '3'], values2 = ['4', '5', '6'
|
||||||
* @param {Object} dataOptions.metricCount
|
* @param {Object} dataOptions.metricCount
|
||||||
* @param {Object} dataOptions.isMultiSeries
|
* @param {Object} dataOptions.isMultiSeries
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
|
||||||
export const timeSeriesGraphData = (panelOptions = {}, dataOptions = {}) => {
|
export const timeSeriesGraphData = (panelOptions = {}, dataOptions = {}) => {
|
||||||
const { metricCount = 1, isMultiSeries = false } = dataOptions;
|
const { metricCount = 1, isMultiSeries = false } = dataOptions;
|
||||||
|
|
||||||
|
@ -68,3 +97,30 @@ export const timeSeriesGraphData = (panelOptions = {}, dataOptions = {}) => {
|
||||||
...panelOptions,
|
...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 = {
|
export const graphDataPrometheusQueryRangeMultiTrack = {
|
||||||
title: 'Super Chart A3',
|
title: 'Super Chart A3',
|
||||||
type: 'heatmap',
|
type: 'heatmap',
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
import * as monitoringUtils from '~/monitoring/utils';
|
import * as monitoringUtils from '~/monitoring/utils';
|
||||||
import * as urlUtils from '~/lib/utils/url_utility';
|
import * as urlUtils from '~/lib/utils/url_utility';
|
||||||
import { TEST_HOST } from 'jest/helpers/test_constants';
|
import { TEST_HOST } from 'jest/helpers/test_constants';
|
||||||
import {
|
import { mockProjectDir, anomalyMockGraphData, barMockData } from './mock_data';
|
||||||
mockProjectDir,
|
|
||||||
singleStatMetricsResult,
|
|
||||||
anomalyMockGraphData,
|
|
||||||
barMockData,
|
|
||||||
} from './mock_data';
|
|
||||||
import { metricsDashboardViewModel, graphData } from './fixture_data';
|
import { metricsDashboardViewModel, graphData } from './fixture_data';
|
||||||
|
import { singleStatGraphData } from './graph_data';
|
||||||
|
|
||||||
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
|
const mockPath = `${TEST_HOST}${mockProjectDir}/-/environments/29/metrics`;
|
||||||
|
|
||||||
|
@ -82,7 +78,7 @@ describe('monitoring/utils', () => {
|
||||||
it('validates data with the query format', () => {
|
it('validates data with the query format', () => {
|
||||||
const validGraphData = monitoringUtils.graphDataValidatorForValues(
|
const validGraphData = monitoringUtils.graphDataValidatorForValues(
|
||||||
true,
|
true,
|
||||||
singleStatMetricsResult,
|
singleStatGraphData(),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(validGraphData).toBe(true);
|
expect(validGraphData).toBe(true);
|
||||||
|
@ -105,7 +101,7 @@ describe('monitoring/utils', () => {
|
||||||
let threeMetrics;
|
let threeMetrics;
|
||||||
let fourMetrics;
|
let fourMetrics;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
oneMetric = singleStatMetricsResult;
|
oneMetric = singleStatGraphData();
|
||||||
threeMetrics = anomalyMockGraphData;
|
threeMetrics = anomalyMockGraphData;
|
||||||
|
|
||||||
const metrics = [...threeMetrics.metrics];
|
const metrics = [...threeMetrics.metrics];
|
||||||
|
|
|
@ -26,6 +26,63 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
||||||
env.merge!(basic_auth_header(username, password))
|
env.merge!(basic_auth_header(username, password))
|
||||||
end
|
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
|
describe '#find_user_from_warden' do
|
||||||
context 'with CSRF token' do
|
context 'with CSRF token' do
|
||||||
before do
|
before do
|
||||||
|
@ -522,8 +579,24 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#validate_access_token!' do
|
describe '#validate_access_token!' do
|
||||||
|
subject { validate_access_token! }
|
||||||
|
|
||||||
let(:personal_access_token) { create(:personal_access_token, user: user) }
|
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
|
it 'returns nil if no access_token present' do
|
||||||
expect(validate_access_token!).to be_nil
|
expect(validate_access_token!).to be_nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -103,6 +103,12 @@ RSpec.describe Jira::Requests::Issues::ListService do
|
||||||
subject
|
subject
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ RSpec.describe Spam::SpamVerdictService do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(service).to receive(:akismet_verdict).and_return(nil)
|
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
|
end
|
||||||
|
|
||||||
context 'if all services return nil' do
|
context 'if all services return nil' do
|
||||||
|
@ -62,7 +62,7 @@ RSpec.describe Spam::SpamVerdictService do
|
||||||
context 'and they are supported' do
|
context 'and they are supported' do
|
||||||
before do
|
before do
|
||||||
allow(service).to receive(:akismet_verdict).and_return(DISALLOW)
|
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
|
end
|
||||||
|
|
||||||
it 'renders the more restrictive verdict' do
|
it 'renders the more restrictive verdict' do
|
||||||
|
@ -73,7 +73,7 @@ RSpec.describe Spam::SpamVerdictService do
|
||||||
context 'and one is supported' do
|
context 'and one is supported' do
|
||||||
before do
|
before do
|
||||||
allow(service).to receive(:akismet_verdict).and_return('nonsense')
|
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
|
end
|
||||||
|
|
||||||
it 'renders the more restrictive verdict' do
|
it 'renders the more restrictive verdict' do
|
||||||
|
@ -84,7 +84,7 @@ RSpec.describe Spam::SpamVerdictService do
|
||||||
context 'and none are supported' do
|
context 'and none are supported' do
|
||||||
before do
|
before do
|
||||||
allow(service).to receive(:akismet_verdict).and_return('nonsense')
|
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
|
end
|
||||||
|
|
||||||
it 'renders the more restrictive verdict' do
|
it 'renders the more restrictive verdict' do
|
||||||
|
@ -149,8 +149,8 @@ RSpec.describe Spam::SpamVerdictService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#spam_verdict' do
|
describe '#external_verdict' do
|
||||||
subject { service.send(:spam_verdict) }
|
subject { service.send(:external_verdict) }
|
||||||
|
|
||||||
context 'if a Spam Check endpoint enabled and set to a URL' do
|
context 'if a Spam Check endpoint enabled and set to a URL' do
|
||||||
let(:spam_check_body) { {} }
|
let(:spam_check_body) { {} }
|
||||||
|
|
|
@ -47,7 +47,7 @@ module SimpleCovEnv
|
||||||
def configure_profile
|
def configure_profile
|
||||||
SimpleCov.configure do
|
SimpleCov.configure do
|
||||||
load_profile 'test_frameworks'
|
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 '/vendor/ruby/'
|
||||||
add_filter '/app/controllers/sherlock/'
|
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 '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 'Migrations', %w[db/migrate db/optional_migrations db/post_migrate] # Matches EE files as well
|
||||||
add_group 'Libraries', %w[/lib /ee/lib]
|
add_group 'Libraries', %w[/lib /ee/lib]
|
||||||
add_group 'Tooling', %w[/danger /haml_lint /rubocop /scripts /tooling]
|
add_group 'Tooling', %w[/haml_lint /rubocop /tooling]
|
||||||
add_group 'QA', '/qa'
|
|
||||||
|
|
||||||
merge_timeout 365.days
|
merge_timeout 365.days
|
||||||
end
|
end
|
||||||
|
|
|
@ -848,10 +848,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.151.0.tgz#099905295d33eb31033f4a48eb3652da2f686239"
|
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.151.0.tgz#099905295d33eb31033f4a48eb3652da2f686239"
|
||||||
integrity sha512-2PTSM8CFhUjeTFKfcq6E/YwPpOVdSVWupf3NhKO/bz/cisSBS5P7aWxaXKIaxy28ySyBKEfKaAT6b4rXTwvVgg==
|
integrity sha512-2PTSM8CFhUjeTFKfcq6E/YwPpOVdSVWupf3NhKO/bz/cisSBS5P7aWxaXKIaxy28ySyBKEfKaAT6b4rXTwvVgg==
|
||||||
|
|
||||||
"@gitlab/ui@17.21.0":
|
"@gitlab/ui@17.22.1":
|
||||||
version "17.21.0"
|
version "17.22.1"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.21.0.tgz#e881bac4540e3db29ee32e1dfd452677a445cd10"
|
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-17.22.1.tgz#368578d04bb49011690911599c22a7d306f5fe99"
|
||||||
integrity sha512-Ijh3QPlB3Y10Sk0f0eZ/rgRIKHGSzAWZLugw9sb+ppcn9OPbb+2vk0ZgCcdIrfkrX3G8tD8q0Ndl3K1nrz6a5g==
|
integrity sha512-elcu2gdvt1Afz3GMrIBQR+eujlA6JetLn44T1UzPHUhlaodT/w+TIj0+uPIbPiD7Oz6uR/sYwBqlZXQdBcVv3Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/standalone" "^7.0.0"
|
"@babel/standalone" "^7.0.0"
|
||||||
"@gitlab/vue-toasted" "^1.3.0"
|
"@gitlab/vue-toasted" "^1.3.0"
|
||||||
|
|
Loading…
Reference in a new issue