Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-18 21:09:57 +00:00
parent 85f7fa54f4
commit bfce95a4c5
107 changed files with 1831 additions and 898 deletions

View File

@ -1 +1 @@
397a8aa41c8b1b159a667fb262aebc644719e074
14370f86aaddaf173ff205148704eab118d8d181

View File

@ -6,6 +6,7 @@ import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import Badge from './badge.vue';
import BadgeForm from './badge_form.vue';
import BadgeList from './badge_list.vue';
import { GlSprintf } from '@gitlab/ui';
export default {
name: 'BadgeSettings',
@ -14,14 +15,15 @@ export default {
BadgeForm,
BadgeList,
GlModal: DeprecatedModal2,
GlSprintf,
},
i18n: {
deleteModalText: s__(
'Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored.',
),
},
computed: {
...mapState(['badgeInModal', 'isEditing']),
deleteModalText() {
return s__(
'Badges|You are going to delete this badge. Deleted badges <strong>cannot</strong> be restored.',
);
},
},
methods: {
...mapActions(['deleteBadge']),
@ -54,7 +56,13 @@ export default {
:link-url="badgeInModal ? badgeInModal.renderedLinkUrl : ''"
/>
</div>
<p v-html="deleteModalText"></p>
<p>
<gl-sprintf :message="$options.i18n.deleteModalText">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</p>
</gl-modal>
<badge-form v-show="isEditing" :is-editing="true" />

View File

@ -1,6 +1,6 @@
<script>
import { escape } from 'lodash';
import { GlModal, GlButton, GlDeprecatedButton, GlFormInput } from '@gitlab/ui';
import { GlModal, GlButton, GlDeprecatedButton, GlFormInput, GlSprintf } from '@gitlab/ui';
import SplitButton from '~/vue_shared/components/split_button.vue';
import { s__, sprintf } from '~/locale';
import csrf from '~/lib/utils/csrf';
@ -30,6 +30,7 @@ export default {
GlButton,
GlDeprecatedButton,
GlFormInput,
GlSprintf,
},
props: {
clusterPath: {
@ -67,18 +68,6 @@ export default {
)
: s__('ClusterIntegration|You are about to remove your cluster integration.');
},
warningToBeRemoved() {
return s__(`ClusterIntegration|
This will permanently delete the following resources:
<ul>
<li>All installed applications and related resources</li>
<li>The <code>gitlab-managed-apps</code> namespace</li>
<li>Any project namespaces</li>
<li><code>clusterroles</code></li>
<li><code>clusterrolebindings</code></li>
</ul>
`);
},
confirmationTextLabel() {
return sprintf(
this.confirmCleanup
@ -144,7 +133,27 @@ export default {
>
<template>
<p>{{ warningMessage }}</p>
<div v-if="confirmCleanup" v-html="warningToBeRemoved"></div>
<div v-if="confirmCleanup">
{{ s__('ClusterIntegration|This will permanently delete the following resources:') }}
<ul>
<li>
{{ s__('ClusterIntegration|All installed applications and related resources') }}
</li>
<li>
<gl-sprintf :message="s__('ClusterIntegration|The %{gitlabNamespace} namespace')">
<template #gitlabNamespace>
<!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
<code>{{ 'gitlab-managed-apps' }}</code>
</template>
</gl-sprintf>
</li>
<li>{{ s__('ClusterIntegration|Any project namespaces') }}</li>
<!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<li><code>clusterroles</code></li>
<li><code>clusterrolebindings</code></li>
<!-- eslint-enable @gitlab/vue-require-i18n-strings -->
</ul>
</div>
<strong v-html="confirmationTextLabel"></strong>
<form ref="form" :action="clusterPath" method="post" class="gl-mb-5">
<input ref="method" type="hidden" name="_method" value="delete" />

View File

@ -1,12 +1,16 @@
<script>
import { escape } from 'lodash';
import { mapState, mapGetters, mapActions } from 'vuex';
import { s__, sprintf } from '~/locale';
import { s__ } from '~/locale';
import { GlSprintf, GlLink } from '@gitlab/ui';
import gkeDropdownMixin from './gke_dropdown_mixin';
export default {
name: 'GkeProjectIdDropdown',
components: {
GlSprintf,
GlLink,
},
mixins: [gkeDropdownMixin],
props: {
docsUrl: {
@ -46,31 +50,23 @@ export default {
return s__('ClusterIntegration|Select project');
},
helpText() {
let message;
if (this.hasErrors) {
return this.errorMessage;
}
if (!this.items) {
message =
'ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.';
return s__(
'ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.',
);
}
message =
this.items && this.items.length
? 'ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.'
: 'ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.';
return sprintf(
s__(message),
{
docsLinkEnd: '&nbsp;<i class="fa fa-external-link" aria-hidden="true"></i></a>',
docsLinkStart: `<a href="${escape(
this.docsUrl,
)}" target="_blank" rel="noopener noreferrer">`,
},
false,
);
return this.items.length
? s__(
'ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.',
)
: s__(
'ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}.',
);
},
errorMessage() {
if (!this.projectHasBillingEnabled) {
@ -80,21 +76,13 @@ export default {
);
}
return sprintf(
s__(
'This project does not have billing enabled. To create a cluster, <a href=%{linkToBilling} target="_blank" rel="noopener noreferrer">enable billing <i class="fa fa-external-link" aria-hidden="true"></i></a> and try again.',
),
{
linkToBilling:
'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral',
},
false,
return s__(
'ClusterIntegration|This project does not have billing enabled. To create a cluster, %{linkToBillingStart}enable billing%{linkToBillingEnd} and try again.',
);
}
return sprintf(
s__('ClusterIntegration|An error occurred while trying to fetch your projects: %{error}'),
{ error: this.gapiError },
return s__(
'ClusterIntegration|An error occurred while trying to fetch your projects: %{error}',
);
},
},
@ -182,7 +170,28 @@ export default {
'text-muted': !hasErrors,
}"
class="form-text"
v-html="helpText"
></span>
>
<gl-sprintf :message="helpText">
<template #linkToBilling="{ content }">
<gl-link
:href="
'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral'
"
target="_blank"
>{{ content }} <i class="fa fa-external-link" aria-hidden="true"></i
></gl-link>
</template>
<template #docsLink="{ content }">
<gl-link :href="docsUrl" target="_blank"
>{{ content }} <i class="fa fa-external-link" aria-hidden="true"></i
></gl-link>
</template>
<template #error>
{{ gapiError }}
</template>
</gl-sprintf>
</span>
</div>
</template>

View File

@ -21,7 +21,7 @@ export const EMPTY_RUNNERS = __(
'Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}',
);
export const ERROR_CONFIG = __(
'Configure a <code>.gitlab-webide.yml</code> file in the <code>.gitlab</code> directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}',
'Configure a %{codeStart}.gitlab-webide.yml%{codeEnd} file in the %{codeStart}.gitlab%{codeEnd} directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}',
);
export const ERROR_PERMISSION = __(
'You do not have permission to run the Web Terminal. Please contact a project administrator.',
@ -34,6 +34,8 @@ export const configCheckError = (status, helpUrl) => {
{
helpStart: `<a href="${escape(helpUrl)}" target="_blank">`,
helpEnd: '</a>',
codeStart: '<code>',
codeEnd: '</code>',
},
false,
);

View File

@ -1,5 +1,2 @@
/* eslint-disable @gitlab/require-i18n-strings */
export const ESC_KEY = 'Escape';
export const ESC_KEY_IE11 = 'Esc'; // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
export const ENTER_KEY = 'Enter';

View File

@ -7,8 +7,8 @@ import {
GlButtonGroup,
GlFormGroup,
GlFormInput,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlNewDropdown as GlDropdown,
GlNewDropdownItem as GlDropdownItem,
GlModal,
GlTooltipDirective,
} from '@gitlab/ui';
@ -40,8 +40,8 @@ export default {
GlButtonGroup,
GlFormGroup,
GlFormInput,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownItem,
GlModal,
GlLink,
Icon,
@ -251,20 +251,20 @@ export default {
</template>
</gl-form-group>
<gl-form-group v-else label-for="alert-query-dropdown" :label="$options.alertQueryText.label">
<gl-deprecated-dropdown
<gl-dropdown
id="alert-query-dropdown"
:text="queryDropdownLabel"
toggle-class="dropdown-menu-toggle qa-alert-query-dropdown"
toggle-class="dropdown-menu-toggle gl-border-1! qa-alert-query-dropdown"
>
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-for="query in relevantQueries"
:key="query.metricId"
data-qa-selector="alert_query_option"
@click="selectQuery(query.metricId)"
>
{{ query.label }}
</gl-deprecated-dropdown-item>
</gl-deprecated-dropdown>
</gl-dropdown-item>
</gl-dropdown>
</gl-form-group>
<gl-button-group class="mb-3" :label="s__('PrometheusAlerts|Operator')">
<gl-deprecated-button

View File

@ -7,7 +7,7 @@ import DashboardHeader from './dashboard_header.vue';
import DashboardPanel from './dashboard_panel.vue';
import { s__ } from '~/locale';
import createFlash from '~/flash';
import { ESC_KEY, ESC_KEY_IE11 } from '~/lib/utils/keys';
import { ESC_KEY } from '~/lib/utils/keys';
import { mergeUrlParams, updateHistory } from '~/lib/utils/url_utility';
import invalidUrl from '~/lib/utils/invalid_url';
import Icon from '~/vue_shared/components/icon.vue';
@ -311,7 +311,7 @@ export default {
},
onKeyup(event) {
const { key } = event;
if (key === ESC_KEY || key === ESC_KEY_IE11) {
if (key === ESC_KEY) {
this.clearExpandedPanel();
}
},

View File

@ -191,7 +191,7 @@ export default {
name="eye-slash"
:size="14"
:title="s__('Notes|Private comments are accessible by internal staff only')"
class="gl-ml-1 gl-text-gray-800 align-middle"
class="gl-ml-1 gl-text-gray-700 align-middle"
/>
<slot name="extra-controls"></slot>
<i

View File

@ -1,6 +1,6 @@
import $ from 'jquery';
import { parseBoolean, getCookie, setCookie, removeCookie } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import { __, sprintf } from '~/locale';
import Tracking from '~/tracking';
const COOKIE_NAME = 'onboarding_issues_settings';
@ -94,8 +94,12 @@ export const showLearnGitLabProjectPopover = () => {
if (!el) return;
const options = {
content: __(
'Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board.',
content: sprintf(
__(
'Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board.',
),
{ strongStart: '<strong>', strongEnd: '</strong>' },
false,
),
};
@ -111,8 +115,12 @@ export const showLearnGitLabIssuesPopover = () => {
if (!el) return;
const options = {
content: __(
'Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board.',
content: sprintf(
__(
'Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board.',
),
{ strongStart: '<strong>', strongEnd: '</strong>' },
false,
),
};

View File

@ -0,0 +1,66 @@
<script>
import { GlBanner } from '@gitlab/ui';
import { s__ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
export default {
components: {
GlBanner,
},
inject: {
svgPath: {
default: '',
},
preferencesBehaviorPath: {
default: '',
},
calloutsPath: {
default: '',
},
calloutsFeatureId: {
default: '',
},
},
i18n: {
title: s__('CustomizeHomepageBanner|Do you want to customize this page?'),
body: s__(
'CustomizeHomepageBanner|This page shows a list of your projects by default but it can be changed to show projects\' activity, groups, your to-do list, assigned issues, assigned merge requests, and more. You can change this under "Homepage content" in your preferences',
),
button_text: s__('CustomizeHomepageBanner|Go to preferences'),
},
data() {
return {
visible: true,
};
},
methods: {
handleClose() {
axios
.post(this.calloutsPath, {
feature_name: this.calloutsFeatureId,
})
.catch(e => {
// eslint-disable-next-line @gitlab/require-i18n-strings, no-console
console.error('Failed to dismiss banner.', e);
});
this.visible = false;
},
},
};
</script>
<template>
<gl-banner
v-if="visible"
:title="$options.i18n.title"
:button-text="$options.i18n.button_text"
:button-link="preferencesBehaviorPath"
:svg-path="svgPath"
@close="handleClose"
>
<p>
{{ $options.i18n.body }}
</p>
</gl-banner>
</template>

View File

@ -1,5 +1,8 @@
import ProjectsList from '~/projects_list';
import initCustomizeHomepageBanner from './init_customize_homepage_banner';
document.addEventListener('DOMContentLoaded', () => {
new ProjectsList(); // eslint-disable-line no-new
initCustomizeHomepageBanner();
});

View File

@ -0,0 +1,16 @@
import Vue from 'vue';
import CustomizeHomepageBanner from './components/customize_homepage_banner.vue';
export default () => {
const el = document.querySelector('.js-customize-homepage-banner');
if (!el) {
return false;
}
return new Vue({
el,
provide: { ...el.dataset },
render: createElement => createElement(CustomizeHomepageBanner),
});
};

View File

@ -1,15 +1,16 @@
<script>
import { escape } from 'lodash';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import { s__, sprintf } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility';
import eventHub from '../event_hub';
import { GlSprintf } from '@gitlab/ui';
export default {
components: {
GlModal: DeprecatedModal2,
GlSprintf,
},
props: {
url: {
@ -45,20 +46,6 @@ export default {
},
);
},
title() {
const label = `<span
class="label color-label"
style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
>${escape(this.labelTitle)}</span>`;
return sprintf(
s__('Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>'),
{
labelTitle: label,
},
false,
);
},
},
methods: {
onSubmit() {
@ -90,7 +77,27 @@ export default {
footer-primary-button-variant="warning"
@submit="onSubmit"
>
<div slot="title" class="modal-title-with-label" v-html="title"></div>
<div slot="title" class="modal-title-with-label">
<gl-sprintf
:message="
s__(
'Labels|%{spanStart}Promote label%{spanEnd} %{labelTitle} %{spanStart}to Group Label?%{spanEnd}',
)
"
>
<template #labelTitle>
<span
class="label color-label"
:style="`background-color: ${labelColor}; color: ${labelTextColor};`"
>
{{ labelTitle }}
</span>
</template>
<template #span="{ content }"
><span>{{ content }}</span></template
>
</gl-sprintf>
</div>
{{ text }}
</gl-modal>

View File

@ -87,16 +87,15 @@ export default class PrometheusMetrics {
if (totalMonitoredMetrics === 0) {
const emptyCommonMetricsText = sprintf(
s__(
'PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>',
),
s__('PrometheusService|No %{docsUrlStart}common metrics%{docsUrlEnd} were found'),
{
docsUrl: this.helpMetricsPath,
docsUrlStart: `<a href="${this.helpMetricsPath}">`,
docsUrlEnd: '</a>',
},
false,
);
this.$monitoredMetricsEmpty.empty();
this.$monitoredMetricsEmpty.append(emptyCommonMetricsText);
this.$monitoredMetricsEmpty.append(`<p class="text-tertiary">${emptyCommonMetricsText}</p>`);
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
} else {
const metricsCountText = sprintf(

View File

@ -1,10 +1,12 @@
<script>
import editFormButtons from './edit_form_buttons.vue';
import { __, sprintf } from '../../../locale';
import { __ } from '../../../locale';
import { GlSprintf } from '@gitlab/ui';
export default {
components: {
editFormButtons,
GlSprintf,
},
props: {
confidential: {
@ -22,25 +24,13 @@ export default {
},
computed: {
confidentialityOnWarning() {
const accessLevel = __('at least Reporter access');
return sprintf(
__(
'You are going to turn on the confidentiality. This means that only team members with %{accessLevel} are able to see and leave comments on the %{issuableType}.',
),
{ issuableType: this.issuableType, accessLevel: `<strong>${accessLevel}</strong>` },
false,
return __(
'You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}.',
);
},
confidentialityOffWarning() {
const accessLevel = __('everyone');
return sprintf(
__(
'You are going to turn off the confidentiality. This means %{accessLevel} will be able to see and leave a comment on this %{issuableType}.',
),
{ issuableType: this.issuableType, accessLevel: `<strong>${accessLevel}</strong>` },
false,
return __(
'You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}.',
);
},
},
@ -51,8 +41,22 @@ export default {
<div class="dropdown show">
<div class="dropdown-menu sidebar-item-warning-message">
<div>
<p v-if="!confidential" v-html="confidentialityOnWarning"></p>
<p v-else v-html="confidentialityOffWarning"></p>
<p v-if="!confidential">
<gl-sprintf :message="confidentialityOnWarning">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
<template #issuableType>{{ issuableType }}</template>
</gl-sprintf>
</p>
<p v-else>
<gl-sprintf :message="confidentialityOffWarning">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
<template #issuableType>{{ issuableType }}</template>
</gl-sprintf>
</p>
<edit-form-buttons :full-path="fullPath" :confidential="confidential" />
</div>
</div>

View File

@ -1,10 +1,11 @@
<script>
import editFormButtons from './edit_form_buttons.vue';
import { __, sprintf } from '../../../locale';
import { GlSprintf } from '@gitlab/ui';
export default {
components: {
editFormButtons,
GlSprintf,
},
props: {
isLocked: {
@ -16,33 +17,41 @@ export default {
type: String,
},
},
computed: {
lockWarning() {
return sprintf(
__(
'Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment.',
),
{ issuableDisplayName: this.issuableDisplayName },
);
},
unlockWarning() {
return sprintf(
__(
'Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment.',
),
{ issuableDisplayName: this.issuableDisplayName },
);
},
},
};
</script>
<template>
<div class="dropdown show">
<div class="dropdown-menu sidebar-item-warning-message" data-testid="warning-text">
<p v-if="isLocked" class="text" v-html="unlockWarning"></p>
<p v-if="isLocked" class="text">
<gl-sprintf
:message="
__(
'Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment.',
)
"
>
<template #issuableDisplayName>{{ issuableDisplayName }}</template>
<template #strong="{ content }"
><strong>{{ content }}</strong></template
>
</gl-sprintf>
</p>
<p v-else class="text" v-html="lockWarning"></p>
<p v-else class="text">
<gl-sprintf
:message="
__(
'Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment.',
)
"
>
<template #issuableDisplayName>{{ issuableDisplayName }}</template>
<template #strong="{ content }"
><strong>{{ content }}</strong></template
>
</gl-sprintf>
</p>
<edit-form-buttons :is-locked="isLocked" :issuable-display-name="issuableDisplayName" />
</div>

View File

@ -1,22 +1,37 @@
<script>
import tooltip from '../../vue_shared/directives/tooltip';
import { __ } from '../../locale';
import { GlSprintf } from '@gitlab/ui';
export default {
i18n: {
removesBranchText: __('%{strongStart}Deletes%{strongEnd} source branch'),
tooltipTitle: __('A user with write access to the source branch selected this option'),
},
components: {
GlSprintf,
},
directives: {
tooltip,
},
created() {
this.removesBranchText = __('<strong>Deletes</strong> source branch');
this.tooltipTitle = __('A user with write access to the source branch selected this option');
},
};
</script>
<template>
<p v-once class="mr-info-list mr-links gl-mb-0">
<span class="status-text" v-html="removesBranchText"> </span>
<i v-tooltip :title="tooltipTitle" :aria-label="tooltipTitle" class="fa fa-question-circle">
<span class="status-text">
<gl-sprintf :message="$options.i18n.removesBranchText">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</span>
<i
v-tooltip
:title="$options.i18n.tooltipTitle"
:aria-label="$options.i18n.tooltipTitle"
class="fa fa-question-circle"
>
</i>
</p>
</template>

View File

@ -125,7 +125,7 @@ $identicon-backgrounds: $identicon-red, $identicon-purple, $identicon-indigo, $i
.identicon {
text-align: center;
vertical-align: top;
color: $gray-800;
color: $gray-700;
background-color: $gray-darker;
// Sizes

View File

@ -28,7 +28,7 @@
}
button {
@include gl-text-gray-800;
@include gl-text-gray-700;
}
}

View File

@ -1,7 +1,7 @@
.badge.badge-pill:not(.gl-badge) {
font-weight: $gl-font-weight-normal;
background-color: $badge-bg;
color: $gray-800;
color: $gray-700;
vertical-align: baseline;
// Do not use this!

View File

@ -38,7 +38,7 @@
}
.broadcast-message-dismiss {
color: $gray-800;
color: $gray-700;
}
}

View File

@ -297,7 +297,7 @@ body {
$gray-200,
$gray-300,
$gray-500,
$gray-800,
$gray-700,
$gray-900,
$white
);
@ -306,7 +306,7 @@ body {
&.ui-light {
@include gitlab-theme(
$gray-500,
$gray-800,
$gray-700,
$gray-500,
$gray-500,
$gray-50,

View File

@ -285,7 +285,7 @@
.select2-highlighted {
.group-result {
.group-path {
color: $gray-800;
color: $gray-700;
}
}
}

View File

@ -170,7 +170,7 @@ $gray-400: #868686 !default;
$gray-500: #666 !default;
$gray-600: #5e5e5e !default;
$gray-700: #525252 !default;
$gray-800: #4f4f4f !default;
$gray-800: #404040 !default;
$gray-900: #303030 !default;
$gray-950: #1f1f1f !default;

View File

@ -38,7 +38,7 @@
}
.badge.badge-pill {
color: var(--ide-text-color, $gray-800);
color: var(--ide-text-color, $gray-700);
background-color: var(--ide-background, $badge-bg);
}

View File

@ -49,7 +49,7 @@
text {
font-weight: bold;
font-size: 12px;
fill: $gray-800;
fill: $gray-700;
}
}
}

View File

@ -336,11 +336,11 @@
}
.label-action {
color: $gray-800;
color: $gray-700;
cursor: pointer;
svg {
fill: $gray-800;
fill: $gray-700;
}
&:hover {

View File

@ -796,7 +796,7 @@
&.ci-status-icon-disabled,
&.ci-status-icon-not-found,
&.ci-status-icon-manual {
@include mini-pipeline-graph-color($white, $gray-500, $gray-800, $gray-900, $gray-950, $black);
@include mini-pipeline-graph-color($white, $gray-500, $gray-700, $gray-900, $gray-950, $black);
}
&.ci-status-icon-created,

View File

@ -13,6 +13,7 @@ class RootController < Dashboard::ProjectsController
before_action :redirect_unlogged_user, if: -> { current_user.nil? }
before_action :redirect_logged_user, if: -> { current_user.present? }
before_action :customize_homepage, only: :index, if: -> { current_user.present? }
# We only need to load the projects when the user is logged in but did not
# configure a dashboard. In which case we render projects. We can do that straight
# from the #index action.
@ -66,6 +67,10 @@ class RootController < Dashboard::ProjectsController
root_urls.exclude?(home_page_url)
end
def customize_homepage
@customize_homepage = experiment_enabled?(:customize_homepage)
end
end
RootController.prepend_if_ee('EE::RootController')

View File

@ -14,7 +14,8 @@ module Resolvers
def resolve(**args)
return unless environment
::PerformanceMonitoring::PrometheusDashboard.find_for(project: environment.project, user: context[:current_user], path: args[:path], options: { environment: environment })
::PerformanceMonitoring::PrometheusDashboard
.find_for(project: environment.project, user: context[:current_user], path: args[:path], options: { environment: environment })
end
end
end

View File

@ -45,8 +45,9 @@ module Types
description: 'Stages of the pipeline',
extras: [:lookahead],
resolver: Resolvers::Ci::PipelineStagesResolver
# TODO: Add triggering user as a type
field :user, Types::UserType, null: true,
description: 'Pipeline user',
resolve: -> (pipeline, _args, _context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, pipeline.user_id).find }
end
end
end

View File

@ -16,6 +16,13 @@ module Types
field :annotations, Types::Metrics::Dashboards::AnnotationType.connection_type, null: true,
description: 'Annotations added to the dashboard',
resolver: Resolvers::Metrics::Dashboards::AnnotationResolver
# In order to maintain backward compatibility we need to return NULL when there are no warnings
# and dashboard validation returns an empty array when there are no issues.
def schema_validation_warnings
warnings = object.schema_validation_warnings
warnings unless warnings.empty?
end
end
# rubocop: enable Graphql/AuthorizeTypes
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Types
# rubocop: disable Graphql/AuthorizeTypes
class UserStatusType < BaseObject
graphql_name 'UserStatus'
markdown_field :message_html, null: true,
description: 'HTML of the user status message'
field :message, GraphQL::STRING_TYPE, null: true,
description: 'User status message'
field :emoji, GraphQL::STRING_TYPE, null: true,
description: 'String representation of emoji'
end
end

View File

@ -18,6 +18,8 @@ module Types
description: 'Human-readable name of the user'
field :state, Types::UserStateEnum, null: false,
description: 'State of the user'
field :email, GraphQL::STRING_TYPE, null: true,
description: 'User email'
field :avatar_url, GraphQL::STRING_TYPE, null: true,
description: "URL of the user's avatar"
field :web_url, GraphQL::STRING_TYPE, null: false,
@ -30,6 +32,8 @@ module Types
field :group_memberships, Types::GroupMemberType.connection_type, null: true,
description: 'Group memberships of the user',
method: :group_members
field :status, Types::UserStatusType, null: true,
description: 'User status'
field :project_memberships, Types::ProjectMemberType.connection_type, null: true,
description: 'Project memberships of the user',
method: :project_members

View File

@ -7,6 +7,7 @@ module UserCalloutsHelper
SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed'
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
CUSTOMIZE_HOMEPAGE = 'customize_homepage'
def show_admin_integrations_moved?
!user_dismissed?(ADMIN_INTEGRATIONS_MOVED)
@ -44,6 +45,10 @@ module UserCalloutsHelper
!user_dismissed?(WEBHOOKS_MOVED)
end
def show_customize_homepage_banner?(customize_homepage)
customize_homepage && !user_dismissed?(CUSTOMIZE_HOMEPAGE)
end
private
def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil)

View File

@ -26,19 +26,10 @@ module BlobViewer
def parse_blob_data
yaml = ::Gitlab::Config::Loader::Yaml.new(blob.data).load_raw!
::PerformanceMonitoring::PrometheusDashboard.from_json(yaml)
nil
Gitlab::Metrics::Dashboard::Validator
.errors(yaml, dashboard_path: blob.path, project: project)
rescue Gitlab::Config::Loader::FormatError => error
wrap_yml_syntax_error(error)
rescue ActiveModel::ValidationError => invalid
invalid.model.errors
end
def wrap_yml_syntax_error(error)
::PerformanceMonitoring::PrometheusDashboard.new.errors.tap do |errors|
errors.add(:'YAML syntax', error.message)
end
[error]
end
end
end

View File

@ -23,6 +23,7 @@ class Discussion
:resolved_by_id,
:system_note_with_references_visible_for?,
:resource_parent,
:save,
to: :first_note

View File

@ -17,12 +17,8 @@ class IndividualNoteDiscussion < Discussion
noteable.supports_replying_to_individual_notes?
end
def convert_to_discussion!(save: false)
first_note.becomes!(Discussion.note_class).to_discussion.tap do
# Save needs to be called on first_note instead of the transformed note
# because of https://gitlab.com/gitlab-org/gitlab-foss/issues/57324
first_note.save if save
end
def convert_to_discussion!
first_note.becomes!(Discussion.note_class).to_discussion
end
def reply_attributes

View File

@ -53,14 +53,18 @@ module PerformanceMonitoring
# This method is planned to be refactored as a part of https://gitlab.com/gitlab-org/gitlab/-/issues/219398
# implementation. For new existing logic was reused to faster deliver MVC
def schema_validation_warnings
self.class.from_json(reload_schema)
nil
rescue ActiveModel::ValidationError => exception
exception.model.errors.map { |attr, error| "#{attr}: #{error}" }
run_custom_validation.map(&:message)
end
private
def run_custom_validation
Gitlab::Metrics::Dashboard::Validator
.errors(reload_schema, dashboard_path: path, project: environment&.project)
rescue Gitlab::Config::Loader::FormatError => error
[error.message]
end
# dashboard finder methods are somehow limited, #find includes checking if
# user is authorised to view selected dashboard, but modifies schema, which in some cases may
# cause false positives returned from validation, and #find_raw does not authorise users

View File

@ -220,6 +220,7 @@ class Repository
prefix_regex.match?(ref)
end
end
cache_method :has_ambiguous_refs?
def expand_ref(ref)
if tag_exists?(ref)
@ -311,12 +312,12 @@ class Repository
end
def expire_tags_cache
expire_method_caches(%i(tag_names tag_count))
expire_method_caches(%i(tag_names tag_count has_ambiguous_refs?))
@tags = nil
end
def expire_branches_cache
expire_method_caches(%i(branch_names merged_branch_names branch_count has_visible_content?))
expire_method_caches(%i(branch_names merged_branch_names branch_count has_visible_content? has_ambiguous_refs?))
@local_branches = nil
@branch_exists_memo = nil
end

View File

@ -19,7 +19,8 @@ module UserCalloutEnums
webhooks_moved: 13,
admin_integrations_moved: 15,
personal_access_token_expiry: 21, # EE-only
suggest_pipeline: 22
suggest_pipeline: 22,
customize_homepage: 23
}
end
end

View File

@ -54,7 +54,8 @@ module Notes
def when_saved(note)
if note.part_of_discussion? && note.discussion.can_convert_to_discussion?
note.discussion.convert_to_discussion!(save: true)
note.discussion.convert_to_discussion!.save
note.clear_memoization(:discussion)
end
todo_service.new_note(note, current_user)

View File

@ -3,6 +3,14 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, dashboard_projects_url(rss_url_options), title: "All activity")
- if show_customize_homepage_banner?(@customize_homepage)
= content_for :customize_homepage_banner do
.d-none.d-md-block{ class: "gl-pt-6! gl-pb-2! #{(container_class unless @no_container)} #{@content_class}" }
.js-customize-homepage-banner{ data: { svg_path: image_path('illustrations/monitoring/getting_started.svg'),
preferences_behavior_path: profile_preferences_path(anchor: 'behavior'),
callouts_path: user_callouts_path,
callouts_feature_id: UserCalloutsHelper::CUSTOMIZE_HOMEPAGE } }
= render_dashboard_gold_trial(current_user)
- page_title _("Projects")

View File

@ -16,6 +16,7 @@
= render_account_recovery_regular_check
= render_if_exists "layouts/header/ee_subscribable_banner"
= render_if_exists "shared/namespace_storage_limit_alert"
= yield :customize_homepage_banner
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
.d-flex

View File

@ -5,7 +5,7 @@
= icon('warning fw')
= _('Metrics Dashboard YAML definition is invalid:')
%ul
- viewer.errors.messages.each do |error|
%li= error.join(': ')
- viewer.errors.each do |error|
%li= error
= link_to _('Learn more'), help_page_path('operations/metrics/dashboards/index.md')

View File

@ -0,0 +1,5 @@
---
title: Fix missing resolve button when replying to notes in MRs
merge_request: 39614
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Create IssueLink for Vulnerabilities that do not have them
merge_request: 39098
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: 'GraphQL: Add user to pipeline + status and email to user + StatusType'
merge_request: 39402
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add default value for file_store to ci_pipeline_artifacts
merge_request: 39349
author:
type: fixed

View File

@ -0,0 +1,6 @@
---
title: Change metrics dashboard schema validation messages into exhaustive list of
all encountered errors.
merge_request: 38925
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Allow query/query_range keys in metrics dashboard to contain numbers
merge_request: 39530
author:
type: changed

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddDefaultValueForFileStoreToPipelineArtifact < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
PIPELINE_ARTIFACT_LOCAL_FILE_STORE = 1
def up
with_lock_retries do
change_column_default :ci_pipeline_artifacts, :file_store, PIPELINE_ARTIFACT_LOCAL_FILE_STORE
end
end
def down
with_lock_retries do
change_column_default :ci_pipeline_artifacts, :file_store, nil
end
end
end

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class CreateIndexVulnerabilitiesFeedbackIssueIdNotNull < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :vulnerability_feedback, :id, where: 'issue_id IS NOT NULL',
name: "index_vulnerability_feedback_on_issue_id_not_null"
end
def down
remove_concurrent_index_by_name :vulnerability_feedback,
:index_vulnerability_feedback_on_issue_id_not_null
end
end

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
class CreateMissingVulnerabilitiesIssueLinks < ActiveRecord::Migration[6.0]
class VulnerabilitiesFeedback < ActiveRecord::Base
include EachBatch
self.table_name = 'vulnerability_feedback'
end
class VulnerabilitiesIssueLink < ActiveRecord::Base
self.table_name = 'vulnerability_issue_links'
LINK_TYPE_CREATED = 2
end
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
# https://github.com/rails/rails/issues/35493
VulnerabilitiesFeedback.where('issue_id IS NOT NULL').each_batch do |relation|
timestamp = Time.now
values = relation
.joins("JOIN vulnerability_occurrences vo ON vo.project_id = vulnerability_feedback.project_id AND vo.report_type = vulnerability_feedback.category AND encode(vo.project_fingerprint, 'hex') = vulnerability_feedback.project_fingerprint")
.pluck(:vulnerability_id, :issue_id)
.map do |v_id, i_id|
{
vulnerability_id: v_id,
issue_id: i_id,
link_type: VulnerabilitiesIssueLink::LINK_TYPE_CREATED,
created_at: timestamp,
updated_at: timestamp
}
end
next if values.empty?
VulnerabilitiesIssueLink.insert_all(
values,
returning: false,
unique_by: %i[vulnerability_id issue_id]
)
end
end
def down
end
end

View File

@ -0,0 +1 @@
36d3db5618a56a0ea03272563fe254590d6af1f7d2610a1f01a5054b1cda1a7d

View File

@ -0,0 +1 @@
e8fc0809b5bd3248dc625602deeaaef16e2db6b33d8eaf51fdcc1c67dee49e17

View File

@ -0,0 +1 @@
c45bbd5aa9143e039d41448f1cb4a2e8e0a7b2c165b50e89b1b829bbbe81f137

View File

@ -10061,7 +10061,7 @@ CREATE TABLE public.ci_pipeline_artifacts (
pipeline_id bigint NOT NULL,
project_id bigint NOT NULL,
size integer NOT NULL,
file_store smallint NOT NULL,
file_store smallint DEFAULT 1 NOT NULL,
file_type smallint NOT NULL,
file_format smallint NOT NULL,
file text,
@ -20971,6 +20971,8 @@ CREATE INDEX index_vulnerability_feedback_on_comment_author_id ON public.vulnera
CREATE INDEX index_vulnerability_feedback_on_issue_id ON public.vulnerability_feedback USING btree (issue_id);
CREATE INDEX index_vulnerability_feedback_on_issue_id_not_null ON public.vulnerability_feedback USING btree (id) WHERE (issue_id IS NOT NULL);
CREATE INDEX index_vulnerability_feedback_on_merge_request_id ON public.vulnerability_feedback USING btree (merge_request_id);
CREATE INDEX index_vulnerability_feedback_on_pipeline_id ON public.vulnerability_feedback USING btree (pipeline_id);

View File

@ -10422,6 +10422,11 @@ type Pipeline {
"""
updatedAt: Time!
"""
Pipeline user
"""
user: User
"""
Permissions for the current user on the resource
"""
@ -16462,6 +16467,11 @@ type User {
"""
avatarUrl: String
"""
User email
"""
email: String
"""
Group memberships of the user
"""
@ -16567,6 +16577,11 @@ type User {
"""
state: UserState!
"""
User status
"""
status: UserStatus
"""
Todos of the user
"""
@ -16705,6 +16720,23 @@ enum UserState {
deactivated
}
type UserStatus {
"""
String representation of emoji
"""
emoji: String
"""
User status message
"""
message: String
"""
HTML of the user status message
"""
messageHtml: String
}
enum VisibilityLevelsEnum {
internal
private

View File

@ -31145,6 +31145,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "user",
"description": "Pipeline user",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "User",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
@ -48275,6 +48289,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "email",
"description": "User email",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "groupMemberships",
"description": "Group memberships of the user",
@ -48526,6 +48554,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "status",
"description": "User status",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "UserStatus",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "todos",
"description": "Todos of the user",
@ -48943,6 +48985,61 @@
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "UserStatus",
"description": null,
"fields": [
{
"name": "emoji",
"description": "String representation of emoji",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "message",
"description": "User status message",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "messageHtml",
"description": "HTML of the user status message",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "VisibilityLevelsEnum",

View File

@ -1604,6 +1604,7 @@ Information about pagination in a connection.
| `startedAt` | Time | Timestamp when the pipeline was started |
| `status` | PipelineStatusEnum! | Status of the pipeline (CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, FAILED, SUCCESS, CANCELED, SKIPPED, MANUAL, SCHEDULED) |
| `updatedAt` | Time! | Timestamp of the pipeline's last activity |
| `user` | User | Pipeline user |
| `userPermissions` | PipelinePermissions! | Permissions for the current user on the resource |
## PipelinePermissions
@ -2434,9 +2435,11 @@ Autogenerated return type of UpdateSnippet
| Name | Type | Description |
| --- | ---- | ---------- |
| `avatarUrl` | String | URL of the user's avatar |
| `email` | String | User email |
| `id` | ID! | ID of the user |
| `name` | String! | Human-readable name of the user |
| `state` | UserState! | State of the user |
| `status` | UserStatus | User status |
| `userPermissions` | UserPermissions! | Permissions for the current user on the resource |
| `username` | String! | Username of the user. Unique within this instance of GitLab |
| `webPath` | String! | Web path of the user |
@ -2448,6 +2451,14 @@ Autogenerated return type of UpdateSnippet
| --- | ---- | ---------- |
| `createSnippet` | Boolean! | Indicates the user can perform `create_snippet` on this resource |
## UserStatus
| Name | Type | Description |
| --- | ---- | ---------- |
| `emoji` | String | String representation of emoji |
| `message` | String | User status message |
| `messageHtml` | String | HTML of the user status message |
## VulnerabilitiesCountByDay
Represents the count of vulnerabilities by severity on a particular day

View File

@ -131,7 +131,7 @@ There are four types of counters which are all found in `usage_data.rb`:
- **Ordinary Batch Counters:** Simple count of a given ActiveRecord_Relation
- **Distinct Batch Counters:** Distinct count of a given ActiveRecord_Relation on given column
- **Alternative Counters:** Used for settings and configurations
- **Redis Counters:** Used for in-memory counts. This method is being deprecated due to data inaccuracies and will be replaced with a persistent method.
- **Redis Counters:** Used for in-memory counts.
NOTE: **Note:**
Only use the provided counter methods. Each counter method contains a built in fail safe to isolate each counter to avoid breaking the entire Usage Ping.
@ -256,8 +256,6 @@ redis_usage_data do
)
```
Note that Redis counters are in the [process of being deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/216330) and you should instead try to use Snowplow events instead. We're in the process of building [self-managed event tracking](https://gitlab.com/gitlab-org/telemetry/-/issues/373) and once this is available, we will convert all Redis counters into Snowplow events.
### Alternative Counters
Handles `StandardError` and fallbacks into -1 this way not all measures fail if we encounter one exception.

View File

@ -0,0 +1,194 @@
---
stage: Monitor
group: Health
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Alert details page
Navigate to the Alert details view by visiting the
[Alert list](alerts.md) and selecting an alert from the
list. You need least Developer [permissions](../../user/permissions.md) to access
alerts.
Alerts provide **Overview** and **Alert details** tabs to give you the right
amount of information you need.
## Alert overview tab
The **Overview** tab provides basic information about the alert:
![Alert Detail Overview](img/alert_detail_overview_v13_1.png)
## Alert details tab
![Alert Full Details](img/alert_detail_full_v13_1.png)
### Update an Alert's status
The Alert detail view enables you to update the Alert Status.
See [Create and manage alerts in GitLab](alerts.md) for more details.
### Create an Issue from an Alert
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
The Alert detail view enables you to create an issue with a
description automatically populated from an alert. To create the issue,
click the **Create Issue** button. You can then view the issue from the
alert by clicking the **View Issue** button.
Closing a GitLab issue associated with an alert changes the alert's status to Resolved.
See [Create and manage alerts in GitLab](alerts.md) for more details about alert statuses.
### Update an Alert's assignee
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
The Alert detail view allows users to update the Alert assignee.
In large teams, where there is shared ownership of an alert, it can be difficult
to track who is investigating and working on it. The Alert detail view
enables you to update the Alert assignee:
NOTE: **Note:**
GitLab currently only supports a single assignee per alert.
1. To display the list of current alerts, click
**{cloud-gear}** **Operations > Alerts**:
![Alert List View Assignee(s)](img/alert_list_assignees_v13_1.png)
1. Select your desired alert to display its **Alert Details View**:
![Alert Details View Assignee(s)](img/alert_details_assignees_v13_1.png)
1. If the right sidebar is not expanded, click
**{angle-double-right}** **Expand sidebar** to expand it.
1. In the right sidebar, locate the **Assignee** and click **Edit**. From the
dropdown menu, select each user you want to assign to the alert. GitLab creates
a [To-Do list item](../../user/todos.md) for each user.
![Alert Details View Assignee(s)](img/alert_todo_assignees_v13_1.png)
To remove an assignee, click **Edit** next to the **Assignee** dropdown menu and
deselect the user from the list of assignees, or click **Unassigned**.
### Alert system notes
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
When you take action on an alert, this is logged as a system note,
which is visible in the Alert Details view. This gives you a linear
timeline of the alert's investigation and assignment history.
The following actions will result in a system note:
- [Updating the status of an alert](#update-an-alerts-status)
- [Creating an issue based on an alert](#create-an-issue-from-an-alert)
- [Assignment of an alert to a user](#update-an-alerts-assignee)
![Alert Details View System Notes](img/alert_detail_system_notes_v13_1.png)
### Create a To-Do from an Alert
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
You can manually create [To-Do list items](../../user/todos.md) for yourself from the
Alert details screen, and view them later on your **To-Do List**. To add a To-Do:
1. To display the list of current alerts, click
**{cloud-gear}** **Operations > Alerts**.
1. Select your desired alert to display its **Alert Management Details View**.
1. Click the **Add a To-Do** button in the right sidebar:
![Alert Details Add A To Do](img/alert_detail_add_todo_v13_1.png)
Click the **To-Do** **{todo-done}** in the navigation bar to view your current To-Do list.
![Alert Details Added to Do](img/alert_detail_added_todo_v13_1.png)
### View an Alert's metrics data
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.2.
To view the metrics for an alert:
1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. Click the alert you want to view.
1. Below the title of the alert, click the **Metrics** tab.
![Alert Metrics View](img/alert_detail_metrics_v13_2.png)
For GitLab-managed Prometheus instances, metrics data is automatically available
for the alert, making it easy to see surrounding behavior. See
[Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances)
for information on setting up alerts.
For externally-managed Prometheus instances, you can configure your alerting rules to
display a chart in the alert. See
[Embedding metrics based on alerts in incident issues](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
for information on how to appropriately configure your alerting rules. See
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
for information on setting up alerts for your self-managed Prometheus instance.
## Use cases for assigning alerts
Consider a team formed by different sections of monitoring, collaborating on a
single application. After an alert surfaces, it's extremely important to
route the alert to the team members who can address and resolve the alert.
Assigning Alerts eases collaboration and delegation. All
assignees are shown in your team's work-flows, and all assignees receive
notifications, simplifying communication and ownership of the alert.
After completing their portion of investigating or fixing the alert, users can
unassign their account from the alert when their role is complete.
The alert status can be updated on the [Alert list](alerts.md) to
reflect if the alert has been resolved.
## View an Alert's logs
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
To view the logs for an alert:
1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. Click the alert you want to view.
1. Below the title of the alert, click the **Metrics** tab.
1. Click the [menu](../metrics/dashboards/index.md#chart-context-menu) of the metric chart to view options.
1. Click **View logs**.
Read [View logs from metrics panel](#view-logs-from-metrics-panel) for additional information.
## Embed metrics in incidents and issues
You can embed metrics anywhere [GitLab Markdown](../../user/markdown.md) is used, such as descriptions,
comments on issues, and merge requests. Embedding metrics helps you share them
when discussing incidents or performance issues. You can output the dashboard directly
into any issue, merge request, epic, or any other Markdown text field in GitLab
by [copying and pasting the link to the metrics dashboard](../metrics/embed.md#embedding-gitlab-managed-kubernetes-metrics).
You can embed both
[GitLab-hosted metrics](../metrics/embed.md) and
[Grafana metrics](../metrics/embed_grafana.md)
in incidents and issue templates.
### Context menu
You can view more details about an embedded metrics panel from the context menu.
To access the context menu, click the **{ellipsis_v}** **More actions** dropdown box
above the upper right corner of the panel. For a list of options, see
[Chart context menu](../metrics/dashboards/index.md#chart-context-menu).
#### View logs from metrics panel
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201846) in GitLab Ultimate 12.8.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 12.9.
Viewing logs from a metrics panel can be useful if you're triaging an application
incident and need to [explore logs](../metrics/dashboards/index.md#chart-context-menu)
from across your application. These logs help you understand what is affecting
your application's performance and resolve any problems.

View File

@ -0,0 +1,118 @@
---
stage: Monitor
group: Health
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Create and manage alerts in GitLab
Users with at least Developer [permissions](../../user/permissions.md) can access
the Alert Management list at **{cloud-gear}** **Operations > Alerts** in your
project's sidebar. The Alert Management list displays alerts sorted by start time,
but you can change the sort order by clicking the headers in the Alert Management list.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.)
The alert list displays the following information:
![Alert List](../../user/project/operations/img/alert_list_v13_1.png)
- **Search** - The alert list supports a simple free text search on the title,
description, monitoring tool, and service fields.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213884) in GitLab 13.1.)
- **Severity** - The current importance of a alert and how much attention it should
receive. For a listing of all statuses, read [Alert Management severity](#alert-severity).
- **Start time** - How long ago the alert fired. This field uses the standard
GitLab pattern of `X time ago`, but is supported by a granular date/time tooltip
depending on the user's locale.
- **Alert description** - The description of the alert, which attempts to capture the most meaningful data.
- **Event count** - The number of times that an alert has fired.
- **Issue** - A link to the incident issue that has been created for the alert.
- **Status** - The current status of the alert:
- **Triggered**: No one has begun investigation.
- **Acknowledged**: Someone is actively investigating the problem.
- **Resolved**: No further work is required.
## Enable Alerts
NOTE: **Note:**
You need at least Maintainer [permissions](../../user/permissions.md) to enable
the Alerts feature.
There are several ways to accept alerts into your GitLab project.
Enabling any of these methods enables the Alert list. After configuring
alerts, visit **{cloud-gear}** **Operations > Alerts** in your project's sidebar
to view the list of alerts.
### Enable GitLab-managed Prometheus alerts
You can install the GitLab-managed Prometheus application on your Kubernetes
cluster. For more information, read
[Managed Prometheus on Kubernetes](../../user/project/integrations/prometheus.md#managed-prometheus-on-kubernetes).
When GitLab-managed Prometheus is installed, the [Alerts list](alerts.md)
is also enabled.
To populate the alerts with data, read
[GitLab-Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances).
### Enable external Prometheus alerts
You can configure an externally-managed Prometheus instance to send alerts
to GitLab. To set up this configuration, read the [configuring Prometheus](../metrics/alerts.md#external-prometheus-instances) documentation. Activating the external Prometheus
configuration also enables the [Alerts list](alerts.md).
To populate the alerts with data, read
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances).
### Enable a Generic Alerts endpoint
GitLab provides the Generic Alerts endpoint so you can accept alerts from a third-party
alerts service. Read the
[instructions for toggling generic alerts](../../user/project/integrations/generic_alerts.md#setting-up-generic-alerts)
to add this option. After configuring the endpoint, the
[Alerts list](alerts.md) is enabled.
To populate the alerts with data, read [Customizing the payload](../../user/project/integrations/generic_alerts.md#customizing-the-payload) for requests to the alerts endpoint.
### Opsgenie integration **(PREMIUM)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
A new way of monitoring Alerts via a GitLab integration is with
[Opsgenie](https://www.atlassian.com/software/opsgenie).
NOTE: **Note:**
If you enable the Opsgenie integration, you can't have other GitLab alert services,
such as [Generic Alerts](../../user/project/integrations/generic_alerts.md) or
Prometheus alerts, active at the same time.
To enable Opsgenie integration:
1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. In the **Integrations** select box, select Opsgenie.
1. Click the **Active** toggle.
1. In the **API URL**, enter the base URL for your Opsgenie integration, such
as `https://app.opsgenie.com/alert/list`.
1. Click **Save changes**.
After enabling the integration, navigate to the Alerts list page at
**{cloud-gear}** **Operations > Alerts**, and click **View alerts in Opsgenie**.
## Alert severity
Each level of alert contains a uniquely shaped and color-coded icon to help
you identify the severity of a particular alert. These severity icons help you
immediately identify which alerts you should prioritize investigating:
![Alert Management Severity System](img/alert_management_severity_v13_0.png)
Alerts contain one of the following icons:
| Severity | Icon | Color (hexadecimal) |
|---|---|---|
| Critical | **{severity-critical}** | `#8b2615` |
| High | **{severity-high}** | `#c0341d` |
| Medium | **{severity-medium}** | `#fca429` |
| Low | **{severity-low}** | `#fdbc60` |
| Info | **{severity-info}** | `#418cd8` |
| Unknown | **{severity-unknown}** | `#bababa` |

View File

@ -0,0 +1,103 @@
---
stage: Monitor
group: Health
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
# Create and manage incidents in GitLab
While no configuration is required to use the [manual features](#create-an-incident-manually)
of incident management, some simple [configuration](#configure-incidents) is needed to automate incident creation.
For users with at least Developer [permissions](../../user/permissions.md), the
Incident Management list is available at **Operations > Incidents**
in your project's sidebar. The list contains the following metrics:
![Incident List](img/incident_list_sort_v13_3.png)
- **Status** - To filter incidents by their status, click **Open**, **Closed**,
or **All** above the incident list.
- **Search** - The Incident list supports a simple free text search, which filters
on the **Title** and **Incident** fields.
- **Incident** - The description of the incident, which attempts to capture the
most meaningful data.
- **Date created** - How long ago the incident was created. This field uses the
standard GitLab pattern of `X time ago`, but is supported by a granular date/time
tooltip depending on the user's locale.
- **Assignees** - The user assigned to the incident.
- **Published** - Displays a green check mark (**{check-circle}**) if the incident is published
to a [Status Page](status_page.md).. **(ULTIMATE)**
The Incident list displays incidents sorted by incident created date.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3).)
To see if a column is sortable, point your mouse at the header. Sortable columns
display an arrow next to the column name.
NOTE: **Note:**
Incidents share the [Issues API](../../user/project/issues/index.md).
## Configure incidents
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in GitLab Ultimate 11.11.
With Maintainer or higher [permissions](../../user/permissions.md), you can enable
or disable Incident Management features in the GitLab user interface
to create issues when alerts are triggered:
1. Navigate to **Settings > Operations > Incidents** and expand
**Incidents**:
![Incident Management Settings](img/incident_management_settings_v13_3.png)
1. For GitLab versions 11.11 and greater, you can select the **Create an issue**
checkbox to create an issue based on your own
[issue templates](../../user/project/description_templates.md#creating-issue-templates).
For more information, see
[Trigger actions from alerts](../metrics/alerts.md#trigger-actions-from-alerts-ultimate) **(ULTIMATE)**.
1. To create issues from alerts, select the template in the **Issue Template**
select box.
1. To send [separate email notifications](index.md#notify-developers-of-alerts) to users
with [Developer permissions](../../user/permissions.md), select
**Send a separate email notification to Developers**.
1. Click **Save changes**.
Appropriately configured alerts include an
[embedded chart](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
for the query corresponding to the alert. You can also configure GitLab to
[close issues](../metrics/alerts.md#trigger-actions-from-alerts-ultimate)
when you receive notification that the alert is resolved.
## Create an incident manually
> [Moved](https://gitlab.com/gitlab-org/monitor/health/-/issues/24) to GitLab core in 13.3.
For users with at least Developer [permissions](../../user/permissions.md), to create a Incident you can take any of the following actions:
- Navigate to **Operations > Incidents** and click **Create Incident**.
- Create a new issue using the `incident` template available when creating it.
- Create a new issue and assign the `incident` label to it.
![Incident List Create](img/incident_list_create_v13_3.png)
## Configure PagerDuty integration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119018) in GitLab 13.3.
You can set up a webhook with PagerDuty to automatically create a GitLab issue
for each PagerDuty incident. This configuration requires you to make changes
in both PagerDuty and GitLab:
1. Sign in as a user with Maintainer [permissions](../../user/permissions.md).
1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
1. Select the **PagerDuty integration** tab:
![PagerDuty incidents integration](img/pagerduty_incidents_integration_v13_3.png)
1. Activate the integration, and save the changes in GitLab.
1. Copy the value of **Webhook URL** for use in a later step.
1. Follow the steps described in the
[PagerDuty documentation](https://support.pagerduty.com/docs/webhooks)
to add the webhook URL to a PagerDuty webhook integration.
To confirm the integration is successful, trigger a test incident from PagerDuty to
confirm that a GitLab issue is created from the incident.

View File

@ -14,324 +14,9 @@ being developed, efficiency and awareness can be increased.
GitLab offers solutions for handling incidents in your applications and services,
such as [setting up Prometheus alerts](#configure-prometheus-alerts),
[displaying metrics](#embed-metrics-in-incidents-and-issues), and sending notifications.
While no configuration is required to use the [manual features](#create-an-incident-manually)
of incident management, some simple [configuration](#configure-incidents) is needed to automate incident creation.
[displaying metrics](alertdetails.md#embed-metrics-in-incidents-and-issues), and sending notifications.
For users with at least Developer [permissions](../../user/permissions.md), the
Incident Management list is available at **Operations > Incidents**
in your project's sidebar. The list contains the following metrics:
![Incident Management List](img/incident_list_sort_v13_3.png)
- **Incident** - The description of the incident, which attempts to capture the
most meaningful data.
- **Date created** - How long ago the incident was created. This field uses the
standard GitLab pattern of `X time ago`, but is supported by a granular date/time
tooltip depending on the user's locale.
- **Assignees** - The user assigned to the incident.
- **Published** - Whether or not an incident is published to the
[Status Page](./status_page.md). **(ULTIMATE)**
The Incident Management list displays incidents sorted by incident created date.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3).)
To see if a column is sortable, point your mouse at the header. Sortable columns
display an arrow next to the column name.
The Incident list supports a simple free text search, which filters on the
**Title** and **Incident** fields.
To filter incidents by their status, click **Open**, **Closed**, or **All**
above the incident list.
NOTE: **Note:**
Incidents share the [Issues API](../../user/project/issues/index.md).
## Enable Alert Management
NOTE: **Note:**
You will need at least Maintainer [permissions](../../user/permissions.md) to enable the Alert Management feature.
There are several ways to accept alerts into your GitLab project, as outlined below.
Enabling any of these methods will allow the Alerts list to display. After configuring
alerts, visit **{cloud-gear}** **Operations > Alerts** in your project's sidebar
to [view the list](#alert-management-list) of alerts.
### Opsgenie integration **(PREMIUM)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
A new way of monitoring Alerts via a GitLab integration is with
[Opsgenie](https://www.atlassian.com/software/opsgenie).
NOTE: **Note:**
If you enable the Opsgenie integration, you cannot have other GitLab alert services,
such as [Generic Alerts](../../user/project/integrations/generic_alerts.md) or
Prometheus alerts, active at the same time.
To enable Opsgenie integration:
1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. In the **Integrations** select box, select Opsgenie.
1. Click the **Active** toggle.
1. In the **API URL**, enter the base URL for your Opsgenie integration, such
as `https://app.opsgenie.com/alert/list`.
1. Click **Save changes**.
After enabling the integration, navigate to the Alerts list page at **{cloud-gear}** **Operations > Alerts**, and click **View alerts in Opsgenie**.
### Enable a Generic Alerts endpoint
GitLab provides the Generic Alerts endpoint so you can accept alerts from a third-party
alerts service. See the
[instructions for toggling generic alerts](../../user/project/integrations/generic_alerts.md#setting-up-generic-alerts)
to add this option. After configuring the endpoint, the
[Alerts list](#alert-management-list) is enabled.
To populate the alerts with data, see [Customizing the payload](../../user/project/integrations/generic_alerts.md#customizing-the-payload) for requests to the alerts endpoint.
### Enable GitLab-managed Prometheus alerts
You can install the GitLab-managed Prometheus application on your Kubernetes
cluster. For more information, see
[Managed Prometheus on Kubernetes](../../user/project/integrations/prometheus.md#managed-prometheus-on-kubernetes).
When GitLab-managed Prometheus is installed, the [Alerts list](#alert-management-list)
is also enabled.
To populate the alerts with data, see
[GitLab-Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances).
### Enable external Prometheus alerts
You can configure an externally-managed Prometheus instance to send alerts
to GitLab. To set up this configuration, see the [configuring Prometheus](../metrics/alerts.md#external-prometheus-instances) documentation. Activating the external Prometheus
configuration also enables the [Alerts list](#alert-management-list).
To populate the alerts with data, see
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances).
## Alert Management severity
Each level of alert contains a uniquely shaped and color-coded icon to help
you identify the severity of a particular alert. These severity icons help you
immediately identify which alerts you should prioritize investigating:
![Alert Management Severity System](img/alert_management_severity_v13_0.png)
Alerts contain one of the following icons:
| Severity | Icon | Color (hexadecimal) |
|---|---|---|
| Critical | **{severity-critical}** | `#8b2615` |
| High | **{severity-high}** | `#c0341d` |
| Medium | **{severity-medium}** | `#fca429` |
| Low | **{severity-low}** | `#fdbc60` |
| Info | **{severity-info}** | `#418cd8` |
| Unknown | **{severity-unknown}** | `#bababa` |
## Alert Management list
NOTE: **Note:**
You will need at least Developer [permissions](../../user/permissions.md) to view the Alert Management list.
You can find the Alert Management list at **{cloud-gear}** **Operations > Alerts** in your project's sidebar.
Each alert contains the following metrics:
![Alert Management List](../../user/project/operations/img/alert_list_v13_1.png)
- **Severity** - The current importance of a alert and how much attention it should receive.
- **Start time** - How long ago the alert fired. This field uses the standard GitLab pattern of `X time ago`, but is supported by a granular date/time tooltip depending on the user's locale.
- **Alert description** - The description of the alert, which attempts to capture the most meaningful data.
- **Event count** - The number of times that an alert has fired.
- **Issue** - A link to the incident issue that has been created for the alert.
- **Status** - The [current status](#alert-management-statuses) of the alert.
### Alert Management list sorting
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
The Alert Management list displays alerts sorted by start time, but you can
change the sort order by clicking the headers in the Alert Management list.
To see if a column is sortable, point your mouse at the header. Sortable columns
display an arrow next to the column name, as shown in this example:
![Alert Management List Sorting](img/alert_list_sort_v13_1.png)
### Searching alerts
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213884) in GitLab 13.1.
The alert list supports a simple free text search.
![Alert List Search](img/alert_list_search_v13_1.png)
This search filters on the following fields:
- Title
- Description
- Monitoring tool
- Service
### Alert Management statuses
Each alert contains a status dropdown to indicate which alerts need investigation.
Standard alert statuses include `triggered`, `acknowledged`, and `resolved`:
- **Triggered**: No one has begun investigation.
- **Acknowledged**: Someone is actively investigating the problem.
- **Resolved**: No further work is required.
## Alert Management details
NOTE: **Note:**
You will need at least Developer [permissions](../../user/permissions.md) to view Alert Management details.
Navigate to the Alert Management detail view by visiting the [Alert Management list](#alert-management-list) and selecting an Alert from the list.
![Alert Management Detail Overview](img/alert_detail_overview_v13_1.png)
![Alert Management Full Details](img/alert_detail_full_v13_1.png)
### Update an Alert's status
The Alert Management detail view enables you to update the Alert Status.
See [Alert Management statuses](#alert-management-statuses) for more details.
### Create an Issue from an Alert
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
The Alert Management detail view enables you to create an issue with a
description automatically populated from an alert. To create the issue,
click the **Create Issue** button. You can then view the issue from the
alert by clicking the **View Issue** button.
Closing a GitLab issue associated with an alert changes the alert's status to Resolved.
See [Alert Management statuses](#alert-management-statuses) for more details about statuses.
### Update an Alert's assignee
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
The Alert Management detail view allows users to update the Alert assignee.
In large teams, where there is shared ownership of an alert, it can be difficult
to track who is investigating and working on it. The Alert Management detail view
enables you to update the Alert assignee:
NOTE: **Note:**
GitLab currently only supports a single assignee per alert.
1. To display the list of current alerts, click
**{cloud-gear}** **Operations > Alerts**:
![Alert Management List View Assignee(s)](img/alert_list_assignees_v13_1.png)
1. Select your desired alert to display its **Alert Management Details View**:
![Alert Management Details View Assignee(s)](img/alert_details_assignees_v13_1.png)
1. If the right sidebar is not expanded, click
**{angle-double-right}** **Expand sidebar** to expand it.
1. In the right sidebar, locate the **Assignee** and click **Edit**. From the
dropdown menu, select each user you want to assign to the alert. GitLab creates
a [To-Do list item](../../user/todos.md) for each user.
![Alert Management Details View Assignee(s)](img/alert_todo_assignees_v13_1.png)
To remove an assignee, click **Edit** next to the **Assignee** dropdown menu and
deselect the user from the list of assignees, or click **Unassigned**.
### Alert system notes
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
When you take action on an alert, this is logged as a system note,
which is visible in the Alert Details view. This gives you a linear
timeline of the alert's investigation and assignment history.
The following actions will result in a system note:
- [Updating the status of an alert](#update-an-alerts-status)
- [Creating an issue based on an alert](#create-an-issue-from-an-alert)
- [Assignment of an alert to a user](#update-an-alerts-assignee)
![Alert Management Details View System Notes](img/alert_detail_system_notes_v13_1.png)
### Create a To-Do from an Alert
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
You can manually create [To-Do list items](../../user/todos.md) for yourself from the
Alert details screen, and view them later on your **To-Do List**. To add a To-Do:
1. To display the list of current alerts, click
**{cloud-gear}** **Operations > Alerts**.
1. Select your desired alert to display its **Alert Management Details View**.
1. Click the **Add a To-Do** button in the right sidebar:
![Alert Management Details Add A To Do](img/alert_detail_add_todo_v13_1.png)
Click the **To-Do** **{todo-done}** in the navigation bar to view your current To-Do list.
![Alert Management Details Added to Do](img/alert_detail_added_todo_v13_1.png)
### View an Alert's metrics data
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.2.
To view the metrics for an alert:
1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. Click the alert you want to view.
1. Below the title of the alert, click the **Metrics** tab.
![Alert Management Metrics View](img/alert_detail_metrics_v13_2.png)
For GitLab-managed Prometheus instances, metrics data is automatically available
for the alert, making it easy to see surrounding behavior. See
[Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances)
for information on setting up alerts.
For externally-managed Prometheus instances, you can configure your alerting rules to
display a chart in the alert. See
[Embedding metrics based on alerts in incident issues](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
for information on how to appropriately configure your alerting rules. See
[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
for information on setting up alerts for your self-managed Prometheus instance.
### View an Alert's logs
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
To view the logs for an alert:
1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
1. Navigate to **{cloud-gear}** **Operations > Alerts**.
1. Click the alert you want to view.
1. Below the title of the alert, click the **Metrics** tab.
1. Click the [menu](../metrics/dashboards/index.md#chart-context-menu) of the metric chart to view options.
1. Click **View logs**.
Read [View logs from metrics panel](#view-logs-from-metrics-panel) for additional information.
## Use cases for assigning alerts
Consider a team formed by different sections of monitoring, collaborating on a
single application. After an alert surfaces, it's extremely important to
route the alert to the team members who can address and resolve the alert.
Assigning Alerts to multiple assignees eases collaboration and delegation. All
assignees are shown in your team's work-flows, and all assignees receive
notifications, simplifying communication and ownership of the alert.
After completing their portion of investigating or fixing the alert, users can
unassign their account from the alert when their role is complete.
The [alerts status](#alert-management-statuses) can be updated to
reflect if the alert has been resolved.
## Alert notifications
### Slack Notifications
@ -341,36 +26,6 @@ You can be alerted via a Slack message when a new alert has been received.
See the [Slack Notifications Service docs](../../user/project/integrations/slack.md) for information on how to set this up.
## Configure incidents
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in GitLab Ultimate 11.11.
With Maintainer or higher [permissions](../../user/permissions.md), you can enable or disable Incident Management features in the GitLab user interface
to create issues when alerts are triggered:
1. Navigate to **Settings > Operations > Incidents** and expand
**Incidents**:
![Incident Management Settings](img/incident_management_settings_v13_3.png)
1. For GitLab versions 11.11 and greater, you can select the **Create an issue**
checkbox to create an issue based on your own
[issue templates](../../user/project/description_templates.md#creating-issue-templates).
For more information, see
[Trigger actions from alerts](../metrics/alerts.md#trigger-actions-from-alerts-ultimate) **(ULTIMATE)**.
1. To create issues from alerts, select the template in the **Issue Template**
select box.
1. To send [separate email notifications](#notify-developers-of-alerts) to users
with [Developer permissions](../../user/permissions.md), select
**Send a separate email notification to Developers**.
1. Click **Save changes**.
Appropriately configured alerts include an
[embedded chart](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
for the query corresponding to the alert. You can also configure GitLab to
[close issues](../metrics/alerts.md#trigger-actions-from-alerts-ultimate)
when you receive notification that the alert is resolved.
### Notify developers of alerts
GitLab can react to the alerts triggered from your applications and services
@ -379,58 +34,8 @@ sends these emails to [owners and maintainers](../../user/permissions.md) of the
These emails contain details of the alert, and a link for more information.
To send separate email notifications to users with
[Developer permissions](../../user/permissions.md), see [Configure incidents](#configure-incidents).
## Incident List
Incidents in GitLab are aggregated in the Incident List, available at
**Operations > Incidents**. This list displays all incidents in GitLab, with tabs
to display open incidents, closed incidents, and all incidents:
![Incident list](img/incident_list.png)
The list displays the following attributes:
- **Incident title**
- **Date created** - in 'time ago' format.
- **Assignees** - the avatar of the user assigned to the incident.
- **Published** - Displays a green check mark (**{check-circle}**) if the incident is published
to a [Status Page](status_page.md).
## Create an incident manually
> [Moved](https://gitlab.com/gitlab-org/monitor/health/-/issues/24) to GitLab core in 13.3.
For users with at least Developer [permissions](../../user/permissions.md), to create a Incident you can take any of the following actions:
- Navigate to **Operations > Incidents** and click **Create Incident**.
- Create a new issue using the `incident` template available when creating it.
- Create a new issue and assign the `incident` label to it.
![Incident List Create](img/incident_list_create_v13_3.png)
## Configure PagerDuty integration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119018) in GitLab 13.3.
You can set up a webhook with PagerDuty to automatically create a GitLab issue
for each PagerDuty incident. This configuration requires you to make changes
in both PagerDuty and GitLab:
1. Sign in as a user with Maintainer [permissions](../../user/permissions.md).
1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
1. Select the **PagerDuty integration** tab:
![PagerDuty incidents integration](img/pagerduty_incidents_integration_v13_3.png)
1. Activate the integration, and save the changes in GitLab.
1. Copy the value of **Webhook URL** for use in a later step.
1. Follow the steps described in the
[PagerDuty documentation](https://support.pagerduty.com/docs/webhooks)
to add the webhook URL to a PagerDuty webhook integration.
To confirm the integration is successful, trigger a test incident from PagerDuty to
confirm that a GitLab issue is created from the incident.
[Developer permissions](../../user/permissions.md), see
[Configure incidents](incidents.md#configure-incidents).
## Configure Prometheus alerts
@ -448,36 +53,6 @@ GitLab can accept alerts from any source through a generic webhook receiver. Whe
[configuring the generic alerts integration](../../user/project/integrations/generic_alerts.md),
GitLab creates a unique endpoint which receives a JSON-formatted, customizable payload.
## Embed metrics in incidents and issues
You can embed metrics anywhere [GitLab Markdown](../../user/markdown.md) is used, such as descriptions,
comments on issues, and merge requests. Embedding metrics helps you share them
when discussing incidents or performance issues. You can output the dashboard directly
into any issue, merge request, epic, or any other Markdown text field in GitLab
by [copying and pasting the link to the metrics dashboard](../metrics/embed.md#embedding-gitlab-managed-kubernetes-metrics).
You can embed both
[GitLab-hosted metrics](../metrics/embed.md) and
[Grafana metrics](../metrics/embed_grafana.md)
in incidents and issue templates.
### Context menu
You can view more details about an embedded metrics panel from the context menu.
To access the context menu, click the **{ellipsis_v}** **More actions** dropdown box
above the upper right corner of the panel. For a list of options, see
[Chart context menu](../metrics/dashboards/index.md#chart-context-menu).
#### View logs from metrics panel
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201846) in GitLab Ultimate 12.8.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 12.9.
Viewing logs from a metrics panel can be useful if you're triaging an application
incident and need to [explore logs](../metrics/dashboards/index.md#chart-context-menu)
from across your application. These logs help you understand what is affecting
your application's performance and resolve any problems.
## Integrate incidents with Slack
Slack slash commands allow you to control GitLab and view GitLab content without leaving Slack.

View File

@ -89,8 +89,8 @@ is no longer used.
| `id` | string | no | Used for associating dashboard metrics with database records. Must be unique across dashboard configuration files. Required for [alerting](../alerts.md) (support not yet enabled, see [relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/27980)). |
| `unit` | string | yes | Defines the unit of the query's return data. |
| `label` | string | no, but highly encouraged | Defines the legend-label for the query. Should be unique within the panel's metrics. Can contain time series labels as interpolated variables. |
| `query` | string | yes if `query_range` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `query_range` | string | yes if `query` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query_range` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `query` | string/number | yes if `query_range` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `query_range` | string/number | yes if `query` is not defined | Defines the Prometheus query to be used to populate the chart/panel. If defined, the `query_range` endpoint of the [Prometheus API](https://prometheus.io/docs/prometheus/latest/querying/api/) will be utilized. |
| `step` | number | no, value is calculated if not defined | Defines query resolution step width in float number of seconds. Metrics on the same panel should use the same `step` value. |
## Dynamic labels
@ -156,21 +156,46 @@ and files with invalid syntax display **Metrics Dashboard YAML definition is inv
When **Metrics Dashboard YAML definition is invalid** at least one of the following messages is displayed:
1. `dashboard: can't be blank` [learn more](#dashboard-top-level-properties)
1. `panel_groups: should be an array of panel_groups objects` [learn more](#dashboard-top-level-properties)
1. `group: can't be blank` [learn more](#panel-group-panel_groups-properties)
1. `panels: should be an array of panels objects` [learn more](#panel-group-panel_groups-properties)
1. `title: can't be blank` [learn more](#panel-panels-properties)
1. `metrics: should be an array of metrics objects` [learn more](#panel-panels-properties)
1. `query: can't be blank` [learn more](#metrics-metrics-properties)
1. `query_range: can't be blank` [learn more](#metrics-metrics-properties)
1. `unit: can't be blank` [learn more](#metrics-metrics-properties)
1. `YAML syntax: The parsed YAML is too big`
1. `[location] is missing required keys: [list of missing keys]` - The entry at
`[location]` is missing a key, or a key has been mistyped. This
example returns the error `root is missing required keys: panel_groups`:
This is displayed when the YAML file is larger than 1 MB.
```yaml
dashboard: Important metrics
group_panels:
- ...
```
1. `YAML syntax: Invalid configuration format`
1. `[data] at [location] is not of type: [type]` - The entry at `[location]` contains
`[data]` which type does not adhere to required types. This example returns the
error `'123' at /panel_groups/0/group is not of type: string`:
This is displayed when the YAML file is empty or does not contain valid YAML.
```yaml
dashboard: Environment metrics
panel_groups:
- group: 123
panels:
...
```
1. `[data] at [location] is not one of: [types]` - The entry at `[location]` contains
`[data]` which is not included in the list of required values. This example returns
the error `'scatterplot-chart' at /panel_groups/0/panels/0/type is not one of: ["area-chart", "line-chart", "anomaly-chart", "bar", "column", "stacked-column", "single-stat", "heatmap"]`:
```yaml
dashboard: Environment metrics
panel_groups:
- group: Network
panels:
- title: Throughput
type: scatterplot-chart
y_label: Requests / Sec
...
```
1. `metric_id must be unique across a project` - At least two metrics entries have
the same `id` attribute, which [must be unique](#metrics-metrics-properties).
1. `The parsed YAML is too big` - The YAML file is larger than 1 MB.
1. `Invalid configuration format` - The YAML file is empty or does not contain valid YAML.
Metrics Dashboard YAML definition validation information is also available as a [GraphQL API field](../../../api/graphql/reference/index.md#metricsdashboard)

View File

@ -116,7 +116,7 @@ In GitLab versions 13.2 and greater, GitLab groups alerts based on their payload
When an incoming alert contains the same payload as another alert (excluding the
`start_time` and `hosts` attributes), GitLab groups these alerts together and
displays a counter on the
[Alert Management List](../../../operations/incident_management/index.md#alert-management-list)
[Alert Management List](../../../operations/incident_management/incidents.md)
and details pages.
If the existing alert is already `resolved`, then a new alert will be created instead.

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -18,7 +18,7 @@ You can find the available integrations under your project's
There are more than 20 integrations to integrate with. Click on the one that you
want to configure.
![Integrations list](img/project_services.png)
![Integrations list](img/project_integrations_v13_3.png)
## Integrations listing

View File

@ -24,8 +24,6 @@ module Gitlab
end
def create_partitions
return unless Feature.enabled?(:postgres_dynamic_partition_creation, default_enabled: true)
Gitlab::AppLogger.info("Checking state of dynamic postgres partitions")
models.each do |model|

View File

@ -59,6 +59,9 @@ module Gitlab
},
contact_sales_btn_in_app: {
tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp'
},
customize_homepage: {
tracking_category: 'Growth::Expansion::Experiment::CustomizeHomepage'
}
}.freeze

View File

@ -76,6 +76,102 @@
- "< 1 saat"
- "< 1 Stunde"
- "< 1시간"
#
# Strings below are fixed in the source code but the translations are still present in CrowdIn so the
# locale files will fail the linter. They can be deleted after next CrowdIn sync, likely in:
# https://gitlab.com/gitlab-org/gitlab/-/issues/226008
#
"This commit was signed with an <strong>unverified</strong> signature.":
plural_id:
translations:
- "このコミットは<strong>検証されていない</strong> 署名でサインされています。"
- "Этот коммит был подписан <strong>непроверенной</strong> подписью."
- "此提交使用 <strong>未经验证的</strong> 签名进行签名。"
- "Цей коміт підписано <strong>неперевіреним</strong> підписом."
- "Esta commit fue firmado con una firma <strong>no verificada</strong>."
"This commit was signed with a <strong>verified</strong> signature and the committer email is verified to belong to the same user.":
plural_id:
translations:
- "このコミットは <strong>検証済み</strong> の署名でサインされており、このコミッターのメールは同じユーザーのものであることが検証されています。"
- "Это коммит был подписан <strong>верифицированной</strong> подписью и коммитер подтвердил, что адрес почты принадлежит ему."
- "此提交使用 <strong>已验证</strong> 的签名进行签名,并且已验证提交者的电子邮件属于同一用户。"
- "Цей коміт підписано <strong>перевіреним</strong> підписом і адреса електронної пошти комітера гарантовано належить тому самому користувачу."
- "Este commit fue firmado con una firma verificada, y <strong>se ha verificado</strong> que la dirección de correo electrónico del committer y la firma pertenecen al mismo usuario."
"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}":
plural_id:
translations:
- "分支 <strong>%{branch_name}</strong> 已創建。如需設置自動部署, 請選擇合適的 GitLab CI Yaml 模板併提交更改。%{link_to_autodeploy_doc}"
- "O branch <strong>%{branch_name}</strong> foi criado. Para configurar o deploy automático, selecione um modelo de Yaml do GitLab CI e commit suas mudanças. %{link_to_autodeploy_doc}"
- "<strong>%{branch_name}</strong> ブランチが作成されました。自動デプロイを設定するには、GitLab CI Yaml テンプレートを選択して、変更をコミットしてください。 %{link_to_autodeploy_doc}"
- "La branch <strong>%{branch_name}</strong> è stata creata. Per impostare un rilascio automatico scegli un template CI di Gitlab e committa le tue modifiche %{link_to_autodeploy_doc}"
- "O ramo <strong>%{branch_name}</strong> foi criado. Para configurar a implantação automática, seleciona um modelo de Yaml do GitLab CI e envia as tuas alterações. %{link_to_autodeploy_doc}"
- "Ветка <strong>%{branch_name}</strong> создана. Для настройки автоматического развертывания выберите YAML-шаблон для GitLab CI и зафиксируйте свои изменения. %{link_to_autodeploy_doc}"
- "已创建分支 <strong>%{branch_name}</strong> 。如需设置自动部署, 请选择合适的 GitLab CI Yaml 模板并提交更改。%{link_to_autodeploy_doc}"
- "Гілка <strong>%{branch_name}</strong> створена. Для настройки автоматичного розгортання виберіть GitLab CI Yaml-шаблон і закомітьте зміни. %{link_to_autodeploy_doc}"
- "Клонът <strong>%{branch_name}</strong> беше създаден. За да настроите автоматичното внедряване, изберете Yaml шаблон за GitLab CI и подайте промените си. %{link_to_autodeploy_doc}"
- "Branch <strong>%{branch_name}</strong> wurde erstellt. Um die automatische Bereitstellung einzurichten, wähle eine GitLab CI Yaml Vorlage und committe deine Änderungen. %{link_to_autodeploy_doc}"
- "<strong>%{branch_name}</strong> 브랜치가 생성되었습니다. 자동 배포를 설정하려면 GitLab CI Yaml 템플릿을 선택하고 변경 사항을 적용하십시오. %{link_to_autodeploy_doc}"
- "La branĉo <strong>%{branch_name}</strong> estis kreita. Por agordi aŭtomatan disponigadon, bonvolu elekti Yaml-ŝablonon por GitLab CI kaj enmeti viajn ŝanĝojn. %{link_to_autodeploy_doc}"
- "La branche <strong>%{branch_name}</strong> a été créée. Pour mettre en place le déploiement automatisé, sélectionnez un modèle de fichier YAML pour lintégration continue (CI) de GitLab, et validez les modifications. %{link_to_autodeploy_doc}"
- "La rama <strong>%{branch_name}</strong> fue creada. Para configurar el auto despliegue, escoge una plantilla Yaml para GitLab CI y envía tus cambios. %{link_to_autodeploy_doc}"
"GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings > General > Visibility%{strong_end} page.":
plural_id:
translations:
- "GitLab Pagesはこのプロジェクトでは無効になっています。 プロジェクトの%{strong_start} 設定> 全般> 可視性%{strong_end}ページで有効にできます。"
- "GitLab Pages отключены для этого проекта. Вы можете включить в поле %{strong_start}Настройки > Общие > Видимость%{strong_end} вашего проекта."
- "此项目禁用GitLab Pages。您可以在您的项目的%{strong_start}设置 > 常规 > 可见性%{strong_end} 页面启用。"
- "GitLab Pages вимкнено для цього проєкту. Ви можете їх увімкнути перейшовши на сторінку проєкту %{strong_start}Налаштування > Загальні > Видимість%{strong_end}."
- "Las páginas de GitLab están deshabilitadas para este proyecto. Puede habilitarlas en los ajustes %{strong_start} de su proyecto > General > Visibilidad%{strong_end}."
"You can invite a new member to <strong>%{project_name}</strong> or invite another group.":
plural_id:
translations:
- "新しいメンバーを<strong>%{project_name} </strong>に招待するか、別のグループを招待することができます。"
- "Podes convidar um novo para <strong>%{project_name}</strong> ou convidar outro grupo."
- "邀请新成员或另一个群组加入<strong>%{project_name}</strong>。"
- "Puede invitar a un nuevo miembro a <strong>%{project_name}</strong> o invitar a otro grupo."
- "<strong>%{project_name}</strong> projesine yeni bir üye davet edebilir veya başka bir grubu davet edebilirsiniz."
- "Вы можете пригласить нового участника в <strong>%{project_name}</strong> или пригласить другую группу."
- "Ви можете запросити нового учасника до <strong>%{project_name}</strong> або запросити іншу групу."
"You can invite a new member to <strong>%{project_name}</strong>.":
plural_id:
translations:
- "新しいメンバーを<strong>%{project_name} </strong>に招待できます。"
- "Podes convidar um novo membro para <strong>%{project_name}</strong>."
- "邀请新成员加入<strong>%{project_name}</strong>。"
- "Puedes invitar a un nuevo miembro a <strong>%{project_name}</strong>."
- "<strong>%{project_name}</strong> projesine yeni bir üye davet edebilirsiniz."
- "Вы можете пригласить нового участника в <strong>%{project_name}</strong>."
- "Ви можете запросити нового учасника до <strong>%{project_name}</strong>."
"You can invite another group to <strong>%{project_name}</strong>.":
plural_id:
translations:
- "他のグループを<strong>%{project_name} </strong>に招待できます。"
- "Podes convidar outro grupo para <strong>%{project_name}</strong>."
- "您可以邀请另一个群组加入<strong>%{project_name}</strong>。"
- "Ви можете запросити нову групу до <strong>%{project_name}</strong>."
- "Puedes invitar a otro grupo a <strong>%{project_name}</strong>."
"Example: <code>192.168.0.0/24</code>. %{read_more_link}.":
plural_id:
translations:
"Note that PostgreSQL %{pg_version_upcoming} will become the minimum required version in GitLab %{gl_version_upcoming} (%{gl_version_upcoming_date}). Please consider upgrading your environment to a supported PostgreSQL version soon, see <a href=\\\"%{pg_version_upcoming_url}\\\">the related epic</a> for details.":
plural_id:
translations:
"Authorize <strong>%{user}</strong> to use your account?":
plural_id:
translations:
"DeployFreeze|Specify times when deployments are not allowed for an environment. The <code>gitlab-ci.yml</code> file must be updated to make deployment jobs aware of the %{freeze_period_link_start}freeze period%{freeze_period_link_end}.":
plural_id:
translations:
"<project name>":
translations:
- "<название проекта>"
- "<project name>"
- "<proje adı>"
- "<naziv projekta>"
- "<ім’я проєкту>"
- "<프로젝트 이름>"
"<strong>Deletes</strong> source branch":
plural_id:
translations:
@ -217,99 +313,3 @@
- "Vous êtes sur le point de dactiver la confidentialité. Cela signifie que seuls les membres de léquipe avec <strong>au moins un accès en tant que rapporteur</strong> seront en mesure de voir et de laisser des commentaires sur le ticket."
- "Va a activar la confidencialidad. Esto significa que solo los miembros del equipo con como mínimo,<strong>acceso como Reporter</strong> podrán ver y dejar comentarios sobre la incidencia."
- "あなたは非公開設定をオンにしようとしています。これは、最低でも<strong>報告権限</strong>を持ったチームメンバーのみが課題を表示したりコメントを残したりすることができるようになるということです。"
#
# Strings below are fixed in the source code but the translations are still present in CrowdIn so the
# locale files will fail the linter. They can be deleted after next CrowdIn sync, likely in:
# https://gitlab.com/gitlab-org/gitlab/-/issues/226008
#
"This commit was signed with an <strong>unverified</strong> signature.":
plural_id:
translations:
- "このコミットは<strong>検証されていない</strong> 署名でサインされています。"
- "Этот коммит был подписан <strong>непроверенной</strong> подписью."
- "此提交使用 <strong>未经验证的</strong> 签名进行签名。"
- "Цей коміт підписано <strong>неперевіреним</strong> підписом."
- "Esta commit fue firmado con una firma <strong>no verificada</strong>."
"This commit was signed with a <strong>verified</strong> signature and the committer email is verified to belong to the same user.":
plural_id:
translations:
- "このコミットは <strong>検証済み</strong> の署名でサインされており、このコミッターのメールは同じユーザーのものであることが検証されています。"
- "Это коммит был подписан <strong>верифицированной</strong> подписью и коммитер подтвердил, что адрес почты принадлежит ему."
- "此提交使用 <strong>已验证</strong> 的签名进行签名,并且已验证提交者的电子邮件属于同一用户。"
- "Цей коміт підписано <strong>перевіреним</strong> підписом і адреса електронної пошти комітера гарантовано належить тому самому користувачу."
- "Este commit fue firmado con una firma verificada, y <strong>se ha verificado</strong> que la dirección de correo electrónico del committer y la firma pertenecen al mismo usuario."
"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}":
plural_id:
translations:
- "分支 <strong>%{branch_name}</strong> 已創建。如需設置自動部署, 請選擇合適的 GitLab CI Yaml 模板併提交更改。%{link_to_autodeploy_doc}"
- "O branch <strong>%{branch_name}</strong> foi criado. Para configurar o deploy automático, selecione um modelo de Yaml do GitLab CI e commit suas mudanças. %{link_to_autodeploy_doc}"
- "<strong>%{branch_name}</strong> ブランチが作成されました。自動デプロイを設定するには、GitLab CI Yaml テンプレートを選択して、変更をコミットしてください。 %{link_to_autodeploy_doc}"
- "La branch <strong>%{branch_name}</strong> è stata creata. Per impostare un rilascio automatico scegli un template CI di Gitlab e committa le tue modifiche %{link_to_autodeploy_doc}"
- "O ramo <strong>%{branch_name}</strong> foi criado. Para configurar a implantação automática, seleciona um modelo de Yaml do GitLab CI e envia as tuas alterações. %{link_to_autodeploy_doc}"
- "Ветка <strong>%{branch_name}</strong> создана. Для настройки автоматического развертывания выберите YAML-шаблон для GitLab CI и зафиксируйте свои изменения. %{link_to_autodeploy_doc}"
- "已创建分支 <strong>%{branch_name}</strong> 。如需设置自动部署, 请选择合适的 GitLab CI Yaml 模板并提交更改。%{link_to_autodeploy_doc}"
- "Гілка <strong>%{branch_name}</strong> створена. Для настройки автоматичного розгортання виберіть GitLab CI Yaml-шаблон і закомітьте зміни. %{link_to_autodeploy_doc}"
- "Клонът <strong>%{branch_name}</strong> беше създаден. За да настроите автоматичното внедряване, изберете Yaml шаблон за GitLab CI и подайте промените си. %{link_to_autodeploy_doc}"
- "Branch <strong>%{branch_name}</strong> wurde erstellt. Um die automatische Bereitstellung einzurichten, wähle eine GitLab CI Yaml Vorlage und committe deine Änderungen. %{link_to_autodeploy_doc}"
- "<strong>%{branch_name}</strong> 브랜치가 생성되었습니다. 자동 배포를 설정하려면 GitLab CI Yaml 템플릿을 선택하고 변경 사항을 적용하십시오. %{link_to_autodeploy_doc}"
- "La branĉo <strong>%{branch_name}</strong> estis kreita. Por agordi aŭtomatan disponigadon, bonvolu elekti Yaml-ŝablonon por GitLab CI kaj enmeti viajn ŝanĝojn. %{link_to_autodeploy_doc}"
- "La branche <strong>%{branch_name}</strong> a été créée. Pour mettre en place le déploiement automatisé, sélectionnez un modèle de fichier YAML pour lintégration continue (CI) de GitLab, et validez les modifications. %{link_to_autodeploy_doc}"
- "La rama <strong>%{branch_name}</strong> fue creada. Para configurar el auto despliegue, escoge una plantilla Yaml para GitLab CI y envía tus cambios. %{link_to_autodeploy_doc}"
"GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings > General > Visibility%{strong_end} page.":
plural_id:
translations:
- "GitLab Pagesはこのプロジェクトでは無効になっています。 プロジェクトの%{strong_start} 設定> 全般> 可視性%{strong_end}ページで有効にできます。"
- "GitLab Pages отключены для этого проекта. Вы можете включить в поле %{strong_start}Настройки > Общие > Видимость%{strong_end} вашего проекта."
- "此项目禁用GitLab Pages。您可以在您的项目的%{strong_start}设置 > 常规 > 可见性%{strong_end} 页面启用。"
- "GitLab Pages вимкнено для цього проєкту. Ви можете їх увімкнути перейшовши на сторінку проєкту %{strong_start}Налаштування > Загальні > Видимість%{strong_end}."
- "Las páginas de GitLab están deshabilitadas para este proyecto. Puede habilitarlas en los ajustes %{strong_start} de su proyecto > General > Visibilidad%{strong_end}."
"You can invite a new member to <strong>%{project_name}</strong> or invite another group.":
plural_id:
translations:
- "新しいメンバーを<strong>%{project_name} </strong>に招待するか、別のグループを招待することができます。"
- "Podes convidar um novo para <strong>%{project_name}</strong> ou convidar outro grupo."
- "邀请新成员或另一个群组加入<strong>%{project_name}</strong>。"
- "Puede invitar a un nuevo miembro a <strong>%{project_name}</strong> o invitar a otro grupo."
- "<strong>%{project_name}</strong> projesine yeni bir üye davet edebilir veya başka bir grubu davet edebilirsiniz."
- "Вы можете пригласить нового участника в <strong>%{project_name}</strong> или пригласить другую группу."
- "Ви можете запросити нового учасника до <strong>%{project_name}</strong> або запросити іншу групу."
"You can invite a new member to <strong>%{project_name}</strong>.":
plural_id:
translations:
- "新しいメンバーを<strong>%{project_name} </strong>に招待できます。"
- "Podes convidar um novo membro para <strong>%{project_name}</strong>."
- "邀请新成员加入<strong>%{project_name}</strong>。"
- "Puedes invitar a un nuevo miembro a <strong>%{project_name}</strong>."
- "<strong>%{project_name}</strong> projesine yeni bir üye davet edebilirsiniz."
- "Вы можете пригласить нового участника в <strong>%{project_name}</strong>."
- "Ви можете запросити нового учасника до <strong>%{project_name}</strong>."
"You can invite another group to <strong>%{project_name}</strong>.":
plural_id:
translations:
- "他のグループを<strong>%{project_name} </strong>に招待できます。"
- "Podes convidar outro grupo para <strong>%{project_name}</strong>."
- "您可以邀请另一个群组加入<strong>%{project_name}</strong>。"
- "Ви можете запросити нову групу до <strong>%{project_name}</strong>."
- "Puedes invitar a otro grupo a <strong>%{project_name}</strong>."
"Example: <code>192.168.0.0/24</code>. %{read_more_link}.":
plural_id:
translations:
"Note that PostgreSQL %{pg_version_upcoming} will become the minimum required version in GitLab %{gl_version_upcoming} (%{gl_version_upcoming_date}). Please consider upgrading your environment to a supported PostgreSQL version soon, see <a href=\\\"%{pg_version_upcoming_url}\\\">the related epic</a> for details.":
plural_id:
translations:
"Authorize <strong>%{user}</strong> to use your account?":
plural_id:
translations:
"DeployFreeze|Specify times when deployments are not allowed for an environment. The <code>gitlab-ci.yml</code> file must be updated to make deployment jobs aware of the %{freeze_period_link_start}freeze period%{freeze_period_link_end}.":
plural_id:
translations:
"<project name>":
translations:
- "<название проекта>"
- "<project name>"
- "<proje adı>"
- "<naziv projekta>"
- "<ім’я проєкту>"
- "<프로젝트 이름>"

View File

@ -47,7 +47,7 @@ module Gitlab
# We need to remove any newlines since our UrlBlocker does not allow
# multiline URLs.
query.squish
query.to_s.squish
end
end
end

View File

@ -8,20 +8,18 @@ module Gitlab
class << self
def validate(content, schema_path = DASHBOARD_SCHEMA_PATH, dashboard_path: nil, project: nil)
errors = _validate(content, schema_path, dashboard_path: dashboard_path, project: project)
errors.empty?
errors(content, schema_path, dashboard_path: dashboard_path, project: project).empty?
end
def validate!(content, schema_path = DASHBOARD_SCHEMA_PATH, dashboard_path: nil, project: nil)
errors = _validate(content, schema_path, dashboard_path: dashboard_path, project: project)
errors = errors(content, schema_path, dashboard_path: dashboard_path, project: project)
errors.empty? || raise(errors.first)
end
private
def _validate(content, schema_path, dashboard_path: nil, project: nil)
client = Validator::Client.new(content, schema_path, dashboard_path: dashboard_path, project: project)
client.execute
def errors(content, schema_path = DASHBOARD_SCHEMA_PATH, dashboard_path: nil, project: nil)
Validator::Client
.new(content, schema_path, dashboard_path: dashboard_path, project: project)
.execute
end
end
end

View File

@ -46,7 +46,7 @@ module Gitlab
def validate_against_schema
schemer.validate(content).map do |error|
Errors::SchemaValidationError.new(error)
::Gitlab::Metrics::Dashboard::Validator::Errors::SchemaValidationError.new(error)
end
end
end

View File

@ -9,8 +9,8 @@
},
"unit": { "type": "string" },
"label": { "type": "string" },
"query": { "type": "string" },
"query_range": { "type": "string" },
"query": { "type": ["string", "number"] },
"query_range": { "type": ["string", "number"] },
"step": { "type": "number" }
}
}

View File

@ -4,7 +4,7 @@
"properties": {
"type": {
"type": "string",
"enum": ["area-chart", "anomaly-chart", "bar", "column", "stacked-column", "single-stat", "heatmap"],
"enum": ["area-chart", "line-chart", "anomaly-chart", "bar", "column", "stacked-column", "single-stat", "heatmap", "gauge"],
"default": "area-chart"
},
"title": { "type": "string" },

View File

@ -697,6 +697,9 @@ msgstr ""
msgid "%{state} epics"
msgstr ""
msgid "%{strongStart}Deletes%{strongEnd} source branch"
msgstr ""
msgid "%{strongStart}Note:%{strongEnd} Once a custom stage has been added you can re-order stages by dragging them into the desired position."
msgstr ""
@ -1075,9 +1078,6 @@ msgstr ""
msgid "< 1 hour"
msgstr ""
msgid "<strong>Deletes</strong> source branch"
msgstr ""
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@ -3761,7 +3761,7 @@ msgstr ""
msgid "Badges|This project has no badges"
msgstr ""
msgid "Badges|You are going to delete this badge. Deleted badges <strong>cannot</strong> be restored."
msgid "Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored."
msgstr ""
msgid "Badges|Your badges"
@ -5117,9 +5117,6 @@ msgstr ""
msgid "ClusterAgent|You have insufficient permissions to create a cluster agent for this project"
msgstr ""
msgid "ClusterIntegration| This will permanently delete the following resources: <ul> <li>All installed applications and related resources</li> <li>The <code>gitlab-managed-apps</code> namespace</li> <li>Any project namespaces</li> <li><code>clusterroles</code></li> <li><code>clusterrolebindings</code></li> </ul>"
msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr ""
@ -5174,6 +5171,9 @@ msgstr ""
msgid "ClusterIntegration|All data will be deleted and cannot be restored."
msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
msgstr ""
@ -5198,6 +5198,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
msgid "ClusterIntegration|Any running pipelines will be canceled."
msgstr ""
@ -5870,6 +5873,9 @@ msgstr ""
msgid "ClusterIntegration|Subnets"
msgstr ""
msgid "ClusterIntegration|The %{gitlabNamespace} namespace"
msgstr ""
msgid "ClusterIntegration|The Amazon Resource Name (ARN) associated with your role. If you do not have a provision role, first create one on %{startAwsLink}Amazon Web Services %{externalLinkIcon}%{endLink} using the above account and external IDs. %{startMoreInfoLink}More information%{endLink}"
msgstr ""
@ -5909,15 +5915,27 @@ msgstr ""
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
msgid "ClusterIntegration|This project does not have billing enabled. To create a cluster, %{linkToBillingStart}enable billing%{linkToBillingEnd} and try again."
msgstr ""
msgid "ClusterIntegration|This will permanently delete the following resources:"
msgstr ""
msgid "ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint."
msgstr ""
msgid "ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
msgid "ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:"
msgstr ""
msgid "ClusterIntegration|To remove your integration, type %{clusterName} to confirm:"
msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
@ -5942,6 +5960,9 @@ msgstr ""
msgid "ClusterIntegration|We could not verify that one of your projects on GCP has billing enabled. Please try again."
msgstr ""
msgid "ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@ -6373,7 +6394,7 @@ msgstr ""
msgid "Configure Tracing"
msgstr ""
msgid "Configure a <code>.gitlab-webide.yml</code> file in the <code>.gitlab</code> directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
msgid "Configure a %{codeStart}.gitlab-webide.yml%{codeEnd} file in the %{codeStart}.gitlab%{codeEnd} directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
msgstr ""
msgid "Configure automatic git checks and housekeeping on repositories."
@ -7429,6 +7450,15 @@ msgstr ""
msgid "Customize your pipeline configuration."
msgstr ""
msgid "CustomizeHomepageBanner|Do you want to customize this page?"
msgstr ""
msgid "CustomizeHomepageBanner|Go to preferences"
msgstr ""
msgid "CustomizeHomepageBanner|This page shows a list of your projects by default but it can be changed to show projects' activity, groups, your to-do list, assigned issues, assigned merge requests, and more. You can change this under \"Homepage content\" in your preferences"
msgstr ""
msgid "Cycle Time"
msgstr ""
@ -8069,8 +8099,8 @@ msgid_plural "Depends on %d merge requests being merged"
msgstr[0] ""
msgstr[1] ""
msgid "Depends on <strong>%d closed</strong> merge request."
msgid_plural "Depends on <strong>%d closed</strong> merge requests."
msgid "Depends on %{strongStart}%{closedCount} closed%{strongEnd} merge request."
msgid_plural "Depends on %{strongStart}%{closedCount} closed%{strongEnd} merge requests."
msgstr[0] ""
msgstr[1] ""
@ -11644,7 +11674,7 @@ msgstr ""
msgid "Go to %{link_to_google_takeout}."
msgstr ""
msgid "Go to <strong>Issues</strong> > <strong>Boards</strong> to access your personalized learning issue board."
msgid "Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board."
msgstr ""
msgid "Go to Webhooks"
@ -13948,7 +13978,7 @@ msgstr ""
msgid "Labels can be applied to issues and merge requests."
msgstr ""
msgid "Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>"
msgid "Labels|%{spanStart}Promote label%{spanEnd} %{labelTitle} %{spanStart}to Group Label?%{spanEnd}"
msgstr ""
msgid "Labels|Promote Label"
@ -14516,7 +14546,7 @@ msgstr ""
msgid "Lock the discussion"
msgstr ""
msgid "Lock this %{issuableDisplayName}? Only <strong>project members</strong> will be able to comment."
msgid "Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
msgstr ""
msgid "Lock to current projects"
@ -19534,9 +19564,6 @@ msgstr ""
msgid "PrometheusService|%{exporters} with %{metrics} were found"
msgstr ""
msgid "PrometheusService|<p class=\"text-tertiary\">No <a href=\"%{docsUrl}\">common metrics</a> were found</p>"
msgstr ""
msgid "PrometheusService|Active"
msgstr ""
@ -19594,6 +19621,9 @@ msgstr ""
msgid "PrometheusService|New metric"
msgstr ""
msgid "PrometheusService|No %{docsUrlStart}common metrics%{docsUrlEnd} were found"
msgstr ""
msgid "PrometheusService|No custom metrics have been created. Create one using the button above"
msgstr ""
@ -25193,9 +25223,6 @@ msgstr ""
msgid "This project does not have a wiki homepage yet"
msgstr ""
msgid "This project does not have billing enabled. To create a cluster, <a href=%{linkToBilling} target=\"_blank\" rel=\"noopener noreferrer\">enable billing <i class=\"fa fa-external-link\" aria-hidden=\"true\"></i></a> and try again."
msgstr ""
msgid "This project has no active access tokens."
msgstr ""
@ -26229,7 +26256,7 @@ msgstr ""
msgid "Unlock the discussion"
msgstr ""
msgid "Unlock this %{issuableDisplayName}? <strong>Everyone</strong> will be able to comment."
msgid "Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
msgstr ""
msgid "Unlocked"
@ -27849,10 +27876,10 @@ msgstr ""
msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{accessLevel} will be able to see and leave a comment on this %{issuableType}."
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
msgid "You are going to turn on the confidentiality. This means that only team members with %{accessLevel} are able to see and leave comments on the %{issuableType}."
msgid "You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}."
msgstr ""
msgid "You are not allowed to push into this branch. Create another branch or open a merge request."
@ -28580,9 +28607,6 @@ msgstr ""
msgid "assign yourself"
msgstr ""
msgid "at least Reporter access"
msgstr ""
msgid "at risk"
msgstr ""
@ -28973,9 +28997,6 @@ msgstr ""
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
msgid "everyone"
msgstr ""
msgid "exceeds the limit of %{bytes} bytes"
msgstr ""
@ -29940,6 +29961,9 @@ msgstr ""
msgid "vulnerability|Add comment & dismiss"
msgstr ""
msgid "vulnerability|Add comment and dismiss"
msgstr ""
msgid "vulnerability|Dismiss vulnerability"
msgstr ""

View File

@ -122,6 +122,30 @@ RSpec.describe RootController do
expect(response).to render_template 'dashboard/projects/index'
end
context 'when experiment is enabled' do
before do
stub_experiment_for_user(customize_homepage: true)
end
it 'renders the default dashboard' do
get :index
expect(assigns[:customize_homepage]).to be true
end
end
context 'when experiment not enabled' do
before do
stub_experiment(customize_homepage: false)
end
it 'renders the default dashboard' do
get :index
expect(assigns[:customize_homepage]).to be false
end
end
end
end
end

View File

@ -95,20 +95,32 @@ RSpec.describe 'Merge request > User posts notes', :js do
end
end
describe 'reply on a deleted conversation' do
before do
visit project_merge_request_path(project, merge_request)
end
it 'shows an error message' do
describe 'replying to a comment' do
it 'makes the discussion resolvable' do
find('.js-reply-button').click
note.delete
page.within('.discussion-reply-holder') do
fill_in 'note[note]', with: 'A reply'
click_button 'Add comment now'
wait_for_requests
expect(page).to have_content('Your comment could not be submitted because discussion to reply to cannot be found')
expect(page).to have_button('Resolve thread')
end
end
context 'when comment is deleted' do
before do
note.delete
end
it 'shows an error message' do
find('.js-reply-button').click
page.within('.discussion-reply-holder') do
fill_in 'note[note]', with: 'A reply'
click_button 'Add comment now'
expect(page).to have_content('Your comment could not be submitted because discussion to reply to cannot be found')
end
end
end
end

View File

@ -589,7 +589,7 @@ RSpec.describe 'File blob', :js do
aggregate_failures do
# shows that dashboard yaml is invalid
expect(page).to have_content('Metrics Dashboard YAML definition is invalid:')
expect(page).to have_content("panel_groups: should be an array of panel_groups objects")
expect(page).to have_content("root is missing required keys: panel_groups")
# shows a learn more link
expect(page).to have_link('Learn more')

View File

@ -48,7 +48,7 @@ panel_groups:
y_label: "y_label"
metrics:
- id: metric_a2
query_range: 'query'
query_range: 2000
label: Legend Label
unit: unit
- title: "Super Chart A1"

View File

@ -10,8 +10,8 @@
],
"properties": {
"id": { "type": "string" },
"query_range": { "type": "string" },
"query": { "type": "string" },
"query_range": { "type": ["string", "number"] },
"query": { "type": ["string", "number"] },
"unit": { "type": "string" },
"label": { "type": "string" },
"track": { "type": "string" },

View File

@ -15,6 +15,8 @@ describe('IDE store terminal messages', () => {
sprintf(
messages.ERROR_CONFIG,
{
codeStart: `<code>`,
codeEnd: `</code>`,
helpStart: `<a href="${escape(TEST_HELP_URL)}" target="_blank">`,
helpEnd: '</a>',
},

View File

@ -2,7 +2,7 @@ import { shallowMount, mount } from '@vue/test-utils';
import VueDraggable from 'vuedraggable';
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import { ESC_KEY, ESC_KEY_IE11 } from '~/lib/utils/keys';
import { ESC_KEY } from '~/lib/utils/keys';
import { objectToQuery } from '~/lib/utils/url_utility';
import axios from '~/lib/utils/axios_utils';
import { dashboardEmptyStates, metricStates } from '~/monitoring/constants';
@ -566,15 +566,6 @@ describe('Dashboard', () => {
undefined,
);
});
it('restores dashboard from full screen by typing the Escape key on IE11', () => {
mockKeyup(ESC_KEY_IE11);
expect(store.dispatch).toHaveBeenCalledWith(
`monitoringDashboard/clearExpandedPanel`,
undefined,
);
});
});
});

View File

@ -0,0 +1,50 @@
import { shallowMount } from '@vue/test-utils';
import CustomizeHomepageBanner from '~/pages/dashboard/projects/index/components/customize_homepage_banner.vue';
import { GlBanner } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
const svgPath = '/illustrations/background';
const provide = {
svgPath,
preferencesBehaviorPath: 'some/behavior/path',
calloutsPath: 'call/out/path',
calloutsFeatureId: 'some-feature-id',
};
const createComponent = () => {
return shallowMount(CustomizeHomepageBanner, { provide });
};
describe('CustomizeHomepageBanner', () => {
let mockAxios;
let wrapper;
beforeEach(() => {
mockAxios = new MockAdapter(axios);
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
mockAxios.restore();
});
it('should render the banner when not dismissed', () => {
expect(wrapper.contains(GlBanner)).toBe(true);
});
it('should close the banner when dismiss is clicked', async () => {
mockAxios.onPost(provide.calloutsPath).replyOnce(200);
expect(wrapper.contains(GlBanner)).toBe(true);
wrapper.find(GlBanner).vm.$emit('close');
await wrapper.vm.$nextTick();
expect(wrapper.contains(GlBanner)).toBe(false);
});
it('includes the body text from options', () => {
expect(wrapper.html()).toContain(wrapper.vm.$options.i18n.body);
});
});

View File

@ -0,0 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Edit Form Dropdown when confidential renders on or off text based on confidentiality 1`] = `
<div
class="dropdown show"
toggleform="function () {}"
updateconfidentialattribute="function () {}"
>
<div
class="dropdown-menu sidebar-item-warning-message"
>
<div>
<p>
<gl-sprintf-stub
message="You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
/>
</p>
<edit-form-buttons-stub
confidential="true"
fullpath=""
/>
</div>
</div>
</div>
`;
exports[`Edit Form Dropdown when not confidential renders "You are going to turn on the confidentiality." in the 1`] = `
<div
class="dropdown show"
toggleform="function () {}"
updateconfidentialattribute="function () {}"
>
<div
class="dropdown-menu sidebar-item-warning-message"
>
<div>
<p>
<gl-sprintf-stub
message="You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}."
/>
</p>
<edit-form-buttons-stub
fullpath=""
/>
</div>
</div>
</div>
`;

View File

@ -23,14 +23,14 @@ describe('Edit Form Dropdown', () => {
});
describe('when not confidential', () => {
it('renders "You are going to turn off the confidentiality." in the ', () => {
it('renders "You are going to turn on the confidentiality." in the ', () => {
createComponent({
confidential: false,
toggleForm,
updateConfidentialAttribute,
});
expect(wrapper.find('p').text()).toContain('You are going to turn on the confidentiality.');
expect(wrapper.element).toMatchSnapshot();
});
});
@ -42,7 +42,7 @@ describe('Edit Form Dropdown', () => {
updateConfidentialAttribute,
});
expect(wrapper.find('p').text()).toContain('You are going to turn off the confidentiality.');
expect(wrapper.element).toMatchSnapshot();
});
});
});

View File

@ -0,0 +1,79 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Edit Form Dropdown In issue page when locked the appropriate warning text is rendered 1`] = `
<div
class="dropdown-menu sidebar-item-warning-message"
data-testid="warning-text"
>
<p
class="text"
>
<gl-sprintf-stub
message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
/>
</p>
<edit-form-buttons-stub
islocked="true"
issuabledisplayname="issue"
/>
</div>
`;
exports[`Edit Form Dropdown In issue page when unlocked the appropriate warning text is rendered 1`] = `
<div
class="dropdown-menu sidebar-item-warning-message"
data-testid="warning-text"
>
<p
class="text"
>
<gl-sprintf-stub
message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
/>
</p>
<edit-form-buttons-stub
issuabledisplayname="issue"
/>
</div>
`;
exports[`Edit Form Dropdown In merge request page when locked the appropriate warning text is rendered 1`] = `
<div
class="dropdown-menu sidebar-item-warning-message"
data-testid="warning-text"
>
<p
class="text"
>
<gl-sprintf-stub
message="Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
/>
</p>
<edit-form-buttons-stub
islocked="true"
issuabledisplayname="merge request"
/>
</div>
`;
exports[`Edit Form Dropdown In merge request page when unlocked the appropriate warning text is rendered 1`] = `
<div
class="dropdown-menu sidebar-item-warning-message"
data-testid="warning-text"
>
<p
class="text"
>
<gl-sprintf-stub
message="Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
/>
</p>
<edit-form-buttons-stub
issuabledisplayname="merge request"
/>
</div>
`;

View File

@ -38,18 +38,16 @@ describe('Edit Form Dropdown', () => {
});
describe.each`
isLocked | lockStatusText | lockAction | warningText
${false} | ${'unlocked'} | ${'Lock'} | ${'Only project members will be able to comment.'}
${true} | ${'locked'} | ${'Unlock'} | ${'Everyone will be able to comment.'}
`('when $lockStatusText', ({ isLocked, lockAction, warningText }) => {
isLocked | lockStatusText
${false} | ${'unlocked'}
${true} | ${'locked'}
`('when $lockStatusText', ({ isLocked }) => {
beforeEach(() => {
createComponent({ props: { isLocked } });
});
it(`the appropriate warning text is rendered`, () => {
expect(findWarningText().text()).toContain(
`${lockAction} this ${issuableDisplayName}? ${warningText}`,
);
expect(findWarningText().element).toMatchSnapshot();
});
});
});

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Types::UserStatusType do
specify { expect(described_class.graphql_name).to eq('UserStatus') }
it 'exposes the expected fields' do
expected_fields = %i[
emoji
message
message_html
]
expect(described_class).to have_graphql_fields(*expected_fields)
end
end

View File

@ -14,11 +14,13 @@ RSpec.describe GitlabSchema.types['User'] do
snippets
name
username
email
avatarUrl
webUrl
webPath
todos
state
status
authoredMergeRequests
assignedMergeRequests
groupMemberships

View File

@ -81,6 +81,36 @@ RSpec.describe UserCalloutsHelper do
end
end
describe '.show_customize_homepage_banner?' do
let(:customize_homepage) { true }
subject { helper.show_customize_homepage_banner?(customize_homepage) }
context 'when user has not dismissed' do
before do
allow(helper).to receive(:user_dismissed?).with(described_class::CUSTOMIZE_HOMEPAGE) { false }
end
context 'when customize_homepage is set' do
it { is_expected.to be true }
end
context 'when customize_homepage is false' do
let(:customize_homepage) { false }
it { is_expected.to be false }
end
end
context 'when user dismissed' do
before do
allow(helper).to receive(:user_dismissed?).with(described_class::CUSTOMIZE_HOMEPAGE) { true }
end
it { is_expected.to be false }
end
end
describe '.render_flash_user_callout' do
it 'renders the flash_user_callout partial' do
expect(helper).to receive(:render)

View File

@ -27,9 +27,17 @@ RSpec.describe Gitlab::Metrics::Dashboard::Stages::MetricEndpointInserter do
transform!
expect(all_metrics).to satisfy_all do |metric|
metric[:prometheus_endpoint_path] == prometheus_path(metric[:query_range].squish)
metric[:prometheus_endpoint_path].present? && !metric[:prometheus_endpoint_path].include?("\n")
end
end
it 'works when query/query_range is a number' do
query = 2000
transform!
expect(all_metrics[1][:prometheus_endpoint_path]).to eq(prometheus_path(query))
end
end
private

View File

@ -34,6 +34,19 @@ RSpec.describe Gitlab::Metrics::Dashboard::Validator::Errors do
it { is_expected.to eq 'root is missing required keys: one' }
end
context 'when there is type mismatch' do
%w(null string boolean integer number array object).each do |expected_type|
context "on type: #{expected_type}" do
let(:type) { expected_type }
let(:details) { nil }
subject { described_class.new(error_hash).message }
it { is_expected.to eq "'property_name' at root is not of type: #{expected_type}" }
end
end
end
end
context 'for nested object' do

View File

@ -143,4 +143,56 @@ RSpec.describe Gitlab::Metrics::Dashboard::Validator do
end
end
end
describe '#errors' do
context 'valid dashboard schema' do
it 'returns no errors' do
expect(described_class.errors(valid_dashboard)).to eq []
end
context 'with duplicate metric_ids' do
it 'returns errors' do
expect(described_class.errors(duplicate_id_dashboard)).to eq [Gitlab::Metrics::Dashboard::Validator::Errors::DuplicateMetricIds.new]
end
end
context 'with dashboard_path and project' do
subject { described_class.errors(valid_dashboard, dashboard_path: 'test/path.yml', project: project) }
context 'with no conflicting metric identifiers in db' do
it { is_expected.to eq [] }
end
context 'with metric identifier present in current dashboard' do
before do
create(:prometheus_metric,
identifier: 'metric_a1',
dashboard_path: 'test/path.yml',
project: project
)
end
it { is_expected.to eq [] }
end
context 'with metric identifier present in another dashboard' do
before do
create(:prometheus_metric,
identifier: 'metric_a1',
dashboard_path: 'some/other/dashboard/path.yml',
project: project
)
end
it { is_expected.to eq [Gitlab::Metrics::Dashboard::Validator::Errors::DuplicateMetricIds.new] }
end
end
end
context 'invalid dashboard schema' do
it 'returns collection of validation errors' do
expect(described_class.errors(invalid_dashboard)).to all be_kind_of(Gitlab::Metrics::Dashboard::Validator::Errors::SchemaValidationError)
end
end
end
end

View File

@ -0,0 +1,122 @@
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200811130433_create_missing_vulnerabilities_issue_links.rb')
RSpec.describe CreateMissingVulnerabilitiesIssueLinks, :migration do
let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
let(:users) { table(:users) }
let(:user) { create_user! }
let(:project) { table(:projects).create!(id: 123, namespace_id: namespace.id) }
let(:scanner) { table(:vulnerability_scanners).create!(project_id: project.id, external_id: 'test', name: 'test scanner') }
let(:issue) { table(:issues).create!(id: 123, project_id: project.id) }
let(:vulnerabilities) { table(:vulnerabilities) }
let(:vulnerabilities_findings) { table(:vulnerability_occurrences) }
let(:vulnerability_feedback) { table(:vulnerability_feedback) }
let(:vulnerability_issue_links) { table(:vulnerability_issue_links) }
let(:vulnerability_identifier) { table(:vulnerability_identifiers).create!(project_id: project.id, external_type: 'test', external_id: 'test', fingerprint: 'test', name: 'test') }
let!(:vulnerability) do
create_vulnerability!(
project_id: project.id,
author_id: user.id
)
end
before do
create_finding!(
vulnerability_id: vulnerability.id,
project_id: project.id,
scanner_id: scanner.id,
primary_identifier_id: vulnerability_identifier.id
)
create_feedback!(
issue_id: issue.id,
project_id: project.id,
author_id: user.id
)
end
context 'with no Vulnerabilities::IssueLinks present' do
it 'creates missing Vulnerabilities::IssueLinks' do
expect(vulnerability_issue_links.count).to eq(0)
migrate!
expect(vulnerability_issue_links.count).to eq(1)
end
end
context 'when an Vulnerabilities::IssueLink already exists' do
before do
vulnerability_issue_links.create!(vulnerability_id: vulnerability.id, issue_id: issue.id)
end
it 'creates no duplicates' do
expect(vulnerability_issue_links.count).to eq(1)
migrate!
expect(vulnerability_issue_links.count).to eq(1)
end
end
private
def create_vulnerability!(project_id:, author_id:, title: 'test', severity: 7, confidence: 7, report_type: 0)
vulnerabilities.create!(
project_id: project_id,
author_id: author_id,
title: title,
severity: severity,
confidence: confidence,
report_type: report_type
)
end
# rubocop:disable Metrics/ParameterLists
def create_finding!(
vulnerability_id:, project_id:, scanner_id:, primary_identifier_id:,
name: "test", severity: 7, confidence: 7, report_type: 0,
project_fingerprint: '123qweasdzxc', location_fingerprint: 'test',
metadata_version: 'test', raw_metadata: 'test', uuid: 'test')
vulnerabilities_findings.create!(
vulnerability_id: vulnerability_id,
project_id: project_id,
name: name,
severity: severity,
confidence: confidence,
report_type: report_type,
project_fingerprint: project_fingerprint,
scanner_id: scanner.id,
primary_identifier_id: vulnerability_identifier.id,
location_fingerprint: location_fingerprint,
metadata_version: metadata_version,
raw_metadata: raw_metadata,
uuid: uuid
)
end
# rubocop:enable Metrics/ParameterLists
# project_fingerprint on Vulnerabilities::Finding is a bytea and we need to match this
def create_feedback!(issue_id:, project_id:, author_id:, feedback_type: 1, category: 0, project_fingerprint: '3132337177656173647a7863')
vulnerability_feedback.create!(
feedback_type: feedback_type,
issue_id: issue.id,
category: category,
project_fingerprint: project_fingerprint,
project_id: project_id,
author_id: author_id
)
end
def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.now, confirmed_at: Time.now)
users.create!(
name: name,
email: email,
username: name,
projects_limit: 0,
user_type: user_type,
confirmed_at: confirmed_at
)
end
end

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