Commit 12f4a202 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents f15e5d07 67d0cc39
......@@ -165,7 +165,7 @@ export default {
</p>
<a
:href="links.webIDEHelpPagePath"
class="btn btn-primary"
class="btn gl-button btn-confirm"
target="_blank"
rel="noopener noreferrer"
>
......
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale';
import { helpPagePath } from '~/helpers/help_page_helper';
import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'PipelineFailed',
components: {
GlLink,
GlSprintf,
statusIcon,
},
computed: {
troubleshootingDocsPath() {
return helpPagePath('ci/troubleshooting', { anchor: 'merge-request-status-messages' });
},
},
i18n: {
failedMessage: s__(
`mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions.`,
),
},
};
</script>
......@@ -14,10 +29,13 @@ export default {
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
{{
s__(`mrWidget|The pipeline for this merge request failed.
Please retry the job or push a new commit to fix the failure`)
}}
<gl-sprintf :message="$options.i18n.failedMessage">
<template #link="{ content }">
<gl-link :href="troubleshootingDocsPath" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</span>
</div>
</div>
......
......@@ -2,19 +2,18 @@
%h4
= _('Variables')
= link_to sprite_icon('question-o', css_class: 'gl-vertical-align-baseline!'), help_page_path('ci/variables/README', anchor: 'custom-environment-variables'), target: '_blank', rel: 'noopener noreferrer'
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= html_escape(_('Environment variables are applied to environments via the Runner. You can use environment variables for passwords, secret keys, etc. Make variables available to the running application by prepending the variable key with %{code_open}K8S_SECRET_%{code_close}. You can set variables to be:')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= _('Variables store information, like passwords and secret keys, that you can use in job scripts. All projects on the instance can use these variables.')
= link_to s_('Learn more.'), help_page_path('ci/variables/README', anchor: 'instance-level-cicd-environment-variables'), target: '_blank', rel: 'noopener noreferrer'
%p
= _('Variables can be:')
%ul
%li
= html_escape(_('%{code_open}Protected%{code_close} variables are only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
= html_escape(_('%{code_open}Masked%{code_close} variables are hidden in job logs (though they must match certain regexp requirements to do so).')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%p
= link_to _('More information'), help_page_path('ci/variables/README', anchor: 'instance-level-cicd-environment-variables')
= html_escape(_('%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('ci/variables/README', anchor: 'masked-variable-requirements'), target: '_blank', rel: 'noopener noreferrer'
......@@ -10,7 +10,7 @@
- if ci_variable_protected_by_default?
%p.settings-message.text-center
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
= s_('Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
= s_('Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
#js-instance-variables{ data: { endpoint: admin_ci_variables_path, group: 'true', maskable_regex: ci_variable_maskable_regex, protected_by_default: ci_variable_protected_by_default?.to_s} }
%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) }
......
......@@ -45,5 +45,5 @@
= render "shared/tokens/scopes_list", token: @application
.form-actions
= link_to 'Edit', edit_admin_application_path(@application), class: 'gl-button btn btn-primary wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger gl-ml-3'
= link_to 'Edit', edit_admin_application_path(@application), class: 'gl-button btn btn-confirm wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'gl-button btn btn-danger gl-ml-3'
......@@ -32,6 +32,6 @@
= render 'shared/projects/dropdown'
= link_to new_project_path, class: 'gl-button btn btn-success' do
New Project
= button_tag "Search", class: "gl-button btn btn-primary btn-search hide"
= button_tag "Search", class: "gl-button btn btn-confirm btn-search hide"
= render 'projects'
......@@ -150,7 +150,7 @@
.form-group.row
.offset-sm-3.col-sm-9
= f.submit _('Transfer'), class: 'gl-button btn btn-primary'
= f.submit _('Transfer'), class: 'gl-button btn btn-confirm'
.card.repository-check
.card-header
......@@ -170,7 +170,7 @@
= link_to sprite_icon('question-o'), help_page_path('administration/repository_checks')
.form-group
= f.submit _('Trigger repository check'), class: 'gl-button btn btn-primary'
= f.submit _('Trigger repository check'), class: 'gl-button btn btn-confirm'
.col-md-6
- if @group
......
= _("These variables are configured in the parent group settings, and will be active in the current project in addition to the project variables.")
= _("These variables are inherited from the parent group.")
......@@ -2,4 +2,4 @@
.bold.table-section.section-40.gl-mr-3
= s_('Key')
.bold.table-section.section-40.gl-mr-3
= s_('Origin')
= s_('Group')
= html_escape(_('Environment variables are applied to environments via the Runner. You can use environment variables for passwords, secret keys, etc. Make variables available to the running application by prepending the variable key with %{code_open}K8S_SECRET_%{code_close}. You can set variables to be:')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= _('Variables store information, like passwords and secret keys, that you can use in job scripts.')
= link_to s_('Learn more.'), help_page_path('ci/variables/README'), target: '_blank', rel: 'noopener noreferrer'
%p
= _('Variables can be:')
%ul
%li
= html_escape(_('%{code_open}Protected%{code_close} variables are only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= html_escape(_('%{code_open}Protected:%{code_close} Only exposed to protected branches or tags.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
%li
= html_escape(_('%{code_open}Masked%{code_close} variables are hidden in job logs (though they must match certain regexp requirements to do so).')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('More information'), help_page_path('ci/variables/README', anchor: 'custom-environment-variables')
= html_escape(_('%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('Learn more.'), help_page_path('ci/variables/README', anchor: 'masked-variable-requirements'), target: '_blank', rel: 'noopener noreferrer'
......@@ -2,7 +2,6 @@
%h4
= _('Variables')
= link_to sprite_icon('question-o', css_class: 'gl-vertical-align-baseline!'), help_page_path('ci/variables/README', anchor: 'custom-environment-variables'), target: '_blank', rel: 'noopener noreferrer'
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
......
......@@ -3,7 +3,7 @@
- if ci_variable_protected_by_default?
%p.settings-message.text-center
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
= s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
= s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
- is_group = !@group.nil?
......
......@@ -12,7 +12,7 @@
= f.label 'Confirm new password', for: "user_password_confirmation"
= f.password_field :password_confirmation, class: "form-control gl-form-input bottom", title: 'This field is required', data: { qa_selector: 'password_confirmation_field' }, required: true
.clearfix
= f.submit "Change your password", class: "gl-button btn btn-info", data: { qa_selector: 'change_password_button' }
= f.submit "Change your password", class: "gl-button btn btn-confirm", data: { qa_selector: 'change_password_button' }
.clearfix.prepend-top-20
%p
......
......@@ -7,7 +7,7 @@
= f.label :email
= f.email_field :email, class: "form-control gl-form-input", required: true, value: params[:user_email], autofocus: true, title: 'Please provide a valid email address.'
.clearfix
= f.submit "Reset password", class: "gl-button btn-info btn"
= f.submit "Reset password", class: "gl-button btn-confirm btn"
.clearfix.prepend-top-20
= render 'devise/shared/sign_in_link'
......@@ -43,5 +43,5 @@
= render "shared/tokens/scopes_list", token: @application
.form-actions
= link_to _('Edit'), edit_oauth_application_path(@application), class: 'gl-button btn btn-primary wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger gl-ml-3'
= link_to _('Edit'), edit_oauth_application_path(@application), class: 'gl-button btn btn-confirm wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'gl-button btn btn-danger gl-ml-3'
......@@ -141,12 +141,12 @@
%img.modal-profile-crop-image{ alt: s_("Profiles|Avatar cropper") }
.crop-controls
.btn-group
%button.btn.btn-primary{ data: { method: 'zoom', option: '-0.1' } }
%button.btn.gl-button.btn-confirm{ data: { method: 'zoom', option: '-0.1' } }
%span
= sprite_icon('search-minus')
%button.btn.btn-primary{ data: { method: 'zoom', option: '0.1' } }
%button.btn.gl-button.btn-confirm{ data: { method: 'zoom', option: '0.1' } }
%span
= sprite_icon('search-plus')
.modal-footer
%button.btn.btn-primary.js-upload-user-avatar{ type: 'button' }
%button.btn.gl-button.btn-confirm.js-upload-user-avatar{ type: 'button' }
= s_("Profiles|Set new profile picture")
.btn-group.ml-0.w-100
- Gitlab::Workhorse::ARCHIVE_FORMATS.each_with_index do |fmt, index|
- archive_path = project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: fmt)
= link_to fmt, external_storage_url_or_path(archive_path), rel: 'nofollow', download: '', class: "gl-button btn btn-xs #{"btn-primary" if index == 0}"
= link_to fmt, external_storage_url_or_path(archive_path), rel: 'nofollow', download: '', class: "gl-button btn btn-xs #{"btn-confirm" if index == 0}"
......@@ -8,7 +8,7 @@
- if @project&.context_commits_enabled? && can_update_merge_request
%p
= _('Push commits to the source branch or add previously merged commits to review them.')
%button.btn.btn-primary.add-review-item-modal-trigger{ type: "button", data: { commits_empty: 'true', context_commits_empty: 'true' } }
%button.btn.gl-button.btn-confirm.add-review-item-modal-trigger{ type: "button", data: { commits_empty: 'true', context_commits_empty: 'true' } }
= _('Add previously merged commits')
- else
%ol#commits-list.list-unstyled
......
......@@ -15,5 +15,5 @@
%p
= link_to _('Unsubscribe'), unsubscribe_sent_notification_path(@sent_notification, force: true),
class: 'gl-button btn btn-primary gl-mr-3'
class: 'gl-button btn btn-confirm gl-mr-3'
= link_to _('Cancel'), new_user_session_path, class: 'gl-button btn gl-mr-3'
---
title: Improve variable settings ui text
merge_request: 52462
author:
type: other
---
title: Change UI text for failed pipeline on an MR
merge_request: 52023
author:
type: changed
---
title: Move btn-primary to btn-confirm class as a part of Pajamas migration
merge_request: 52090
author: Yogi (@yo)
type: changed
......@@ -222,6 +222,29 @@ This also applies if the pipeline has not been created yet, or if you are waitin
for an external CI service. If you don't use pipelines for your project, then you
should disable **Pipelines must succeed** so you can accept merge requests.
### "The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the troubleshooting documentation to see other possible actions." message
This message is shown if the [merge request pipeline](merge_request_pipelines/index.md),
[merged results pipeline](merge_request_pipelines/pipelines_for_merged_results/index.md),
or [merge train pipeline](merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md)
has failed or been canceled.
If a merge request pipeline or merged result pipeline was canceled or failed, you can:
- Re-run the entire pipeline by clicking **Run pipeline** in the pipeline tab in the merge request.
- [Retry only the jobs that failed](pipelines/index.md#view-pipelines). If you re-run the entire pipeline, this is not necessary.
- Push a new commit to fix the failure.
If the merge train pipeline has failed, you can:
- Check the failure and determine if you can use the [`/merge` quick action](../user/project/quick_actions.md) to immediately add the merge request to the train again.
- Re-run the entire pipeline by clicking **Run pipeline** in the pipeline tab in the merge request, then add the merge request to the train again.
- Push a commit to fix the failure, then add the merge request to the train again.
If the merge train pipeline was canceled before the merge request was merged, without a failure, you can:
- Add it to the train again.
## Pipeline warnings
Pipeline configuration warnings are shown when you:
......
......@@ -16,13 +16,15 @@ to them.
> - The New Epic form [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211533) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
> - In [GitLab 13.7](https://gitlab.com/gitlab-org/gitlab/-/issues/229621) and later, the New Epic button on the Epics list opens the New Epic form.
> - In [GitLab 13.9](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45948) and later, you can create a new epic from an empty Roadmap.
To create an epic in the group you're in:
1. Get to the New Epic form:
- From the **Epics** list in your group, select the **New Epic** button.
- From an epic in your group, select the **New Epic** button.
- From the **Epics** list in your group, select **New epic**.
- From an epic in your group, select **New epic**.
- From anywhere, in the top menu, select **New...** (**{plus-square}**) **> New epic**.
- In an empty [roadmap](../roadmap/index.md), select **New epic**.
![New epic from an open epic](img/new_epic_from_groups_v13.7.png)
......@@ -39,7 +41,7 @@ To create an epic in the group you're in:
## Edit an epic
After you create an epic, you can edit change the following details:
After you create an epic, you can edit the following details:
- Title
- Description
......@@ -152,6 +154,9 @@ To make an epic confidential:
## Manage issues assigned to an epic
This section collects instructions for all the things you can do with [issues](../../project/issues/index.md)
in relation to epics.
### Add a new issue to an epic
You can add an existing issue to an epic, or create a new issue that's
......
<script>
import { mapState, mapActions } from 'vuex';
import {
GlForm,
GlFormInput,
GlFormCheckbox,
GlIcon,
GlButton,
GlTooltipDirective,
} from '@gitlab/ui';
import { __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
components: {
GlFormCheckbox,
GlIcon,
GlButton,
GlForm,
GlFormInput,
},
directives: {
autofocusonshow,
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagsMixin()],
props: {
alignRight: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
...mapState(['newEpicTitle', 'newEpicConfidential', 'epicCreateInProgress']),
buttonLabel() {
return this.epicCreateInProgress ? __('Creating epic') : __('Create epic');
},
isEpicCreateDisabled() {
return !this.newEpicTitle.length;
},
epicTitle: {
set(value) {
this.setEpicCreateTitle({
newEpicTitle: value,
});
},
get() {
return this.newEpicTitle;
},
},
epicConfidential: {
set(value) {
this.setEpicCreateConfidential({
newEpicConfidential: value,
});
},
get() {
return this.newEpicConfidential;
},
},
},
methods: {
...mapActions(['setEpicCreateTitle', 'createEpic', 'setEpicCreateConfidential']),
},
};
</script>
<template>
<div class="dropdown epic-create-dropdown">
<gl-button
category="primary"
variant="success"
data-qa-selector="new_epic_button"
data-toggle="dropdown"
>
{{ __('New epic') }}
</gl-button>
<div :class="{ 'dropdown-menu-right': alignRight }" class="dropdown-menu">
<gl-form>
<gl-form-input
ref="epicTitleInput"
v-model="epicTitle"
v-autofocusonshow
:disabled="epicCreateInProgress"
:placeholder="__('Title')"
type="text"
class="form-control"
data-qa-selector="epic_title_field"
@keyup.enter.exact="createEpic"
/>
<gl-form-checkbox
v-model="epicConfidential"
class="mt-3 mb-3 mr-0"
data-qa-selector="confidential_epic_checkbox"
><span> {{ __('Make this epic confidential') }} </span>
<span
v-gl-tooltip.viewport.top.hover
:title="
__(
'This epic and its child elements will only be visible to team members with at minimum Reporter access.',
)
"
:aria-label="
__(
'This epic and its child elements will only be visible to team members with at minimum Reporter access.',
)
"
>
<gl-icon name="question" :size="12"
/></span>
</gl-form-checkbox>
<gl-button
:disabled="isEpicCreateDisabled"
:loading="epicCreateInProgress"
category="primary"
variant="success"
class="gl-mt-3"
data-qa-selector="create_epic_button"
@click.stop="createEpic"
>{{ buttonLabel }}</gl-button
>
</gl-form>
</div>
</div>
</template>
......@@ -9,10 +9,9 @@ import { parseIssuableData } from '~/issue_show/utils/parse_data';
import createStore from './store';
import EpicApp from './components/epic_app.vue';
import EpicCreateApp from './components/epic_create.vue';
export default (epicCreate = false) => {
const el = document.getElementById(epicCreate ? 'epic-create-root' : 'epic-app-root');
export default () => {
const el = document.getElementById('epic-app-root');
if (!el) {
return false;
......@@ -21,28 +20,6 @@ export default (epicCreate = false) => {
const store = createStore();
store.registerModule('labelsSelect', labelsSelectModule());
if (epicCreate) {
return new Vue({
el,
store,
components: { EpicCreateApp },
created() {
this.setEpicMeta({
endpoint: el.dataset.endpoint,
});
},
methods: {
...mapActions(['setEpicMeta']),
},
render: (createElement) =>
createElement('epic-create-app', {
props: {
alignRight: el.dataset.alignRight,
},
}),
});
}
const epicMeta = convertObjectPropsToCamelCase(JSON.parse(el.dataset.meta), { deep: true });
const epicData = parseIssuableData(el);
......
<script>
/* eslint-disable vue/no-v-html */
import { GlButton } from '@gitlab/ui';
import { GlButton, GlSafeHtmlDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import { dateInWords } from '~/lib/utils/datetime_utility';
import CommonMixin from '../mixins/common_mixin';
import { emptyStateDefault, emptyStateWithFilters } from '../constants';
import initEpicCreate from '../../epic/epic_bundle';
export default {
components: {
GlButton,
},
directives: {
SafeHtml: GlSafeHtmlDirective,
},
mixins: [CommonMixin],
inject: ['newEpicPath', 'listEpicsPath', 'epicsDocsPath'],
props: {
presetType: {
type: String,
......@@ -31,10 +32,6 @@ export default {
type: Boolean,
required: true,
},
newEpicEndpoint: {
type: String,
required: true,
},
emptyStateIllustrationPath: {
type: String,
required: true,
......@@ -96,8 +93,7 @@ export default {
'GroupRoadmap|To view the roadmap, add a start or due date to one of the %{linkStart}child epics%{linkEnd}.',
),
{
linkStart:
'<a href="https://docs.gitlab.com/ee/user/group/epics/#multi-level-child-epics" target="_blank" rel="noopener noreferrer nofollow">',
linkStart: `<a href="${this.epicsDocsPath}#multi-level-child-epics" target="_blank" rel="noopener noreferrer nofollow">`,
linkEnd: '</a>',
},
false,
......@@ -116,36 +112,38 @@ export default {
});
},
},
mounted() {
// If filters are not applied and yet user
// is seeing empty state, we need to show
// `New epic` button, so boot-up Epic app
// in create mode.
if (!this.hasFiltersApplied) {
initEpicCreate(true);
}
},
};
</script>
<template>
<div class="row empty-state">
<div class="col-12">
<div class="svg-content"><img :src="emptyStateIllustrationPath" /></div>
<div class="svg-content">
<img :src="emptyStateIllustrationPath" data-testid="illustration" />
</div>
</div>
<div class="col-12">
<div class="text-content">
<h4>{{ message }}</h4>
<p v-html="subMessage"></p>
<div class="text-center">
<div
<h4 data-testid="title">{{ message }}</h4>
<p v-safe-html="subMessage" data-testid="sub-title"></p>
<div class="gl-text-center">
<gl-button
v-if="!hasFiltersApplied"
id="epic-create-root"
:data-endpoint="newEpicEndpoint"
></div>
<gl-button :title="__('List')" :href="newEpicEndpoint">{{
s__('View epics list')
}}</gl-button>
:href="newEpicPath"
variant="success"
class="gl-mt-3 gl-sm-mt-0! gl-w-full gl-sm-w-auto!"
data-testid="new-epic-button"
>
{{ __('New epic') }}
</gl-button>
<gl-button
:href="listEpicsPath"
class="gl-mt-3 gl-sm-mt-0! gl-sm-ml-3 gl-w-full gl-sm-w-auto!"
data-testid="list-epics-button"
>
{{ __('View epics list') }}
</gl-button>
</div>
</div>
</div>
......
......@@ -37,10 +37,6 @@ export default {
type: String,
required: true,
},
newEpicEndpoint: {
type: String,
required: true,
},
emptyStateIllustrationPath: {
type: String,
required: true,
......@@ -179,7 +175,6 @@ export default {
:timeframe-start="timeframeStart"
:timeframe-end="timeframeEnd"
:has-filters-applied="hasFiltersApplied"
:new-epic-endpoint="newEpicEndpoint"
:empty-state-illustration-path="emptyStateIllustrationPath"
:is-child-epics="isChildEpics"
/>
......
......@@ -50,6 +50,15 @@ export default () => {
components: {
roadmapApp,
},
provide() {
const { dataset } = this.$options.el;
return {
newEpicPath: dataset.newEpicPath,
listEpicsPath: dataset.listEpicsPath,
epicsDocsPath: dataset.epicsDocsPath,
};
},
data() {
const supportedPresetTypes = Object.keys(PRESET_TYPES);
const { dataset } = this.$options.el;
......@@ -83,7 +92,6 @@ export default () => {
basePath: dataset.epicsPath,
fullPath: dataset.fullPath,
epicIid: dataset.iid,
newEpicEndpoint: dataset.newEpicEndpoint,
groupLabelsEndpoint: dataset.groupLabelsEndpoint,
groupMilestonesEndpoint: dataset.groupMilestonesEndpoint,
epicsState: dataset.epicsState,
......@@ -119,7 +127,6 @@ export default () => {
return createElement('roadmap-app', {
props: {
presetType: this.presetType,
newEpicEndpoint: this.newEpicEndpoint,
emptyStateIllustrationPath: this.emptyStateIllustrationPath,
},
});
......
......@@ -25,4 +25,4 @@
= license_key
.modal-footer.form-actions
%button.btn.gl-button.btn-default{ type: 'button', data: { dismiss: 'modal' } } Cancel
= f.submit 'Install license', class: 'gl-button btn btn-primary'
= f.submit 'Install license', class: 'gl-button btn btn-confirm'
......@@ -56,4 +56,4 @@
= _('Unless otherwise agreed to in writing with GitLab, by clicking "Upload License" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}.').html_safe % { eula_link_start: eula_link_start, eula_url: eula_url, eula_link_end: '</a>'.html_safe }
.form-actions
= f.submit 'Upload License', class: 'gl-button btn btn-primary', disabled: true, id: 'js-upload-license'
= f.submit 'Upload License', class: 'gl-button btn btn-confirm', disabled: true, id: 'js-upload-license'
......@@ -66,7 +66,9 @@
full_path: @group.full_path,
empty_state_illustration: image_path('illustrations/epics/roadmap.svg'),
has_filters_applied: 'false',
new_epic_endpoint: group_epics_path(@group),
new_epic_path: new_group_epic_path(@group),
list_epics_path: group_epics_path(@group),
epics_docs_path: help_page_path('user/group/epics/index'),
preset_type: roadmap_layout,
epics_state: 'all',
sorted_by: roadmap_sort_order,
......
......@@ -20,7 +20,9 @@
full_path: @group.full_path,
empty_state_illustration: image_path('illustrations/epics/roadmap.svg'),
has_filters_applied: "#{has_filters_applied}",
new_epic_endpoint: group_epics_path(@group),
new_epic_path: new_group_epic_path(@group),
list_epics_path: group_epics_path(@group),
epics_docs_path: help_page_path('user/group/epics/index'),
group_labels_endpoint: group_labels_path(@group, format: :json),
group_milestones_endpoint: group_milestones_path(@group, format: :json),
preset_type: roadmap_layout,
......
......@@ -9,7 +9,7 @@
.form-text.text-muted.js-scim-token-helper-text
%span
= s_('GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to ')
%button.btn.gl-button.btn-primary.btn-link.d-inline.align-baseline.js-reset-scim-token{ type: 'button' }
%button.btn.gl-button.btn-confirm.btn-link.d-inline.align-baseline.js-reset-scim-token{ type: 'button' }
= _('reset it.')
%span.d-none
= s_("GroupSAML|Make sure you save this token — you won't be able to access it again.")
......
---
title: New epic button in Epic Roadmap empty state should direct the user to a full
epic creation page
merge_request: 45948
author:
type: changed
import Vue from 'vue';
import EpicCreate from 'ee/epic/components/epic_create.vue';
import createStore from 'ee/epic/store';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { mockEpicMeta } from '../mock_data';
describe('EpicCreateComponent', () => {
let vm;
let store;
beforeEach(() => {
const Component = Vue.extend(EpicCreate);
store = createStore();
store.dispatch('setEpicMeta', mockEpicMeta);
vm = mountComponentWithStore(Component, {
store,
});
});
afterEach(() => {
vm.$destroy();
});
describe('computed', () => {
describe('buttonLabel', () => {
it('returns string `Create epic` when `epicCreateInProgress` is false', () => {
vm.$store.state.epicCreateInProgress = false;
expect(vm.buttonLabel).toBe('Create epic');
});
it('returns string `Creating epic` when `epicCreateInProgress` is true', () => {
vm.$store.state.epicCreateInProgress = true;
expect(vm.buttonLabel).toBe('Creating epic');
});
});
describe('isEpicCreateDisabled', () => {
it('returns `true` when `newEpicTitle` is an empty string', () => {
vm.$store.state.newEpicTitle = '';
expect(vm.isEpicCreateDisabled).toBe(true);
});
it('returns `false` when `newEpicTitle` is not empty', () => {
vm.$store.state.newEpicTitle = 'foobar';
expect(vm.isEpicCreateDisabled).toBe(false);
});
});
describe('epicTitle', () => {
describe('set', () => {
it('calls `setEpicCreateTitle` with param `value`', () => {
jest.spyOn(vm, 'setEpicCreateTitle');
const newEpicTitle = 'foobar';
vm.epicTitle = newEpicTitle;
expect(vm.setEpicCreateTitle).toHaveBeenCalledWith(
expect.objectContaining({
newEpicTitle,
}),
);
});
});
describe('get', () => {
it('returns value of `newEpicTitle` from state', () => {
const newEpicTitle = 'foobar';
vm.$store.state.newEpicTitle = newEpicTitle;
expect(vm.epicTitle).toBe(newEpicTitle);
});
});
});
describe('epicConfidential', () => {
describe('set', () => {
it('calls `setEpicCreateConfidential` with param `value`', () => {
jest.spyOn(vm, 'setEpicCreateConfidential');
const newEpicConfidential = true;
vm.epicConfidential = newEpicConfidential;
expect(vm.setEpicCreateConfidential).toHaveBeenCalledWith(
expect.objectContaining({
newEpicConfidential,
}),
);
});
});
describe('get', () => {
it('returns value of `newEpicConfidential` from state', () => {
const newEpicConfidential = true;
vm.$store.state.newEpicConfidential = newEpicConfidential;
expect(vm.epicConfidential).toBe(newEpicConfidential);
});
});
});
});
describe('template', () => {
it('renders component container element with classes `dropdown` & `epic-create-dropdown`', () => {
expect(vm.$el.classList.contains('dropdown')).toBe(true);
expect(vm.$el.classList.contains('epic-create-dropdown')).toBe(true);
});
it('renders new epic button element', () => {
const newEpicButtonEl = vm.$el.querySelector('button.btn-success');
expect(newEpicButtonEl).not.toBeNull();
expect(newEpicButtonEl.innerText.trim()).toBe('New epic');
});
it('renders new epic dropdown menu element', () => {
const dropdownMenuEl = vm.$el.querySelector('.dropdown-menu');
expect(dropdownMenuEl).not.toBeNull();
});
it('renders epic input textbox element', () => {
const inputEl = vm.$el.querySelector('.dropdown-menu input.form-control');
expect(inputEl).not.toBeNull();
expect(inputEl.placeholder).toBe('Title');
});
it('renders create epic button element', () => {
const createEpicButtonEl = vm.$el.querySelector('.dropdown-menu button.btn-success');
expect(createEpicButtonEl).not.toBeNull();
expect(createEpicButtonEl.innerText.trim()).toBe('Create epic');
});
});
});
......@@ -17,7 +17,6 @@ import {
mockFormattedEpic,
mockFormattedChildEpic2,
mockGroupId,
mockNewEpicEndpoint,
mockSortedBy,
mockSvgPath,
mockTimeframeInitialDate,
......@@ -35,7 +34,6 @@ describe('RoadmapApp', () => {
const emptyStateIllustrationPath = mockSvgPath;
const epics = [mockFormattedEpic];
const hasFiltersApplied = true;
const newEpicEndpoint = mockNewEpicEndpoint;
const presetType = PRESET_TYPES.MONTHS;
const timeframe = getTimeframeForMonthsView(mockTimeframeInitialDate);
......@@ -44,7 +42,6 @@ describe('RoadmapApp', () => {
localVue,
propsData: {
emptyStateIllustrationPath,
newEpicEndpoint,
presetType,
},
provide: {
......@@ -122,10 +119,6 @@ describe('RoadmapApp', () => {
expect(wrapper.find(EpicsListEmpty).props('isChildEpics')).toBe(false);
});
it('contains endpoint to create a new epic', () => {
expect(wrapper.find(EpicsListEmpty).props('newEpicEndpoint')).toBe(mockNewEpicEndpoint);
});
it('contains the preset type', () => {
expect(wrapper.find(EpicsListEmpty).props('presetType')).toBe(presetType);
});
......
......@@ -374,10 +374,10 @@ msgstr ""
msgid "%{board_target} not found"
msgstr ""
msgid "%{code_open}Masked%{code_close} variables are hidden in job logs (though they must match certain regexp requirements to do so)."
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
msgid "%{code_open}Protected%{code_close} variables are only exposed to protected branches or tags."
msgid "%{code_open}Protected:%{code_close} Only exposed to protected branches or tags."
msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
......@@ -11025,13 +11025,10 @@ msgstr ""
msgid "Environment scope"
msgstr ""
msgid "Environment variables are applied to environments via the Runner. You can use environment variables for passwords, secret keys, etc. Make variables available to the running application by prepending the variable key with %{code_open}K8S_SECRET_%{code_close}. You can set variables to be:"
msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default."
msgstr ""
msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default"
msgstr ""
msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default"
msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
msgstr ""
msgid "Environment:"
......@@ -17223,9 +17220,6 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
msgid "Make this epic confidential"
msgstr ""
msgid "Makes this issue confidential."
msgstr ""
......@@ -20205,9 +20199,6 @@ msgstr ""
msgid "Or you can choose one of the suggested colors below"
msgstr ""
msgid "Origin"
msgstr ""
msgid "Orphaned member"
msgstr ""
......@@ -28865,7 +28856,7 @@ msgstr ""
msgid "These runners are specific to this project."
msgstr ""
msgid "These variables are configured in the parent group settings, and will be active in the current project in addition to the project variables."
msgid "These variables are inherited from the parent group."
msgstr ""
msgid "Third Party Advisory Link"
......@@ -29039,9 +29030,6 @@ msgstr ""
msgid "This epic already has the maximum number of child epics."
msgstr ""
msgid "This epic and its child elements will only be visible to team members with at minimum Reporter access."
msgstr ""
msgid "This epic does not exist or you don't have sufficient permission."
msgstr ""
......@@ -31310,6 +31298,15 @@ msgstr ""
msgid "Variables"
msgstr ""
msgid "Variables can be:"
msgstr ""
msgid "Variables store information, like passwords and secret keys, that you can use in job scripts."
msgstr ""
msgid "Variables store information, like passwords and secret keys, that you can use in job scripts. All projects on the instance can use these variables."
msgstr ""
msgid "Various container registry settings."
msgstr ""
......@@ -34179,7 +34176,7 @@ msgstr ""
msgid "mrWidget|The changes will be merged into"
msgstr ""
msgid "mrWidget|The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure"
msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions."
msgstr ""
msgid "mrWidget|The source branch HEAD has recently changed. Please reload the page and review the changes before merging"
......
......@@ -57,7 +57,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js do
wait_for_requests
expect(page).to have_css('button[disabled="disabled"]', text: 'Merge')
expect(page).to have_content('Please retry the job or push a new commit to fix the failure')
expect(page).to have_content('The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the troubleshooting documentation to see other possible actions.')
end
end
......@@ -70,7 +70,7 @@ RSpec.describe 'Merge request > User merges only if pipeline succeeds', :js do
wait_for_requests
expect(page).not_to have_button 'Merge'
expect(page).to have_content('Please retry the job or push a new commit to fix the failure')
expect(page).to have_content('The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the troubleshooting documentation to see other possible actions.')
end
end
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PipelineFailed should render error message with a disabled merge button 1`] = `
<div
class="mr-widget-body media"
>
<status-icon-stub
showdisabledbutton="true"
status="warning"
/>
<div
class="media-body space-children"
>
<span
class="bold"
>
<gl-sprintf-stub
message="The pipeline for this merge request did not complete. Push a new commit to fix the failure or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions."
/>
</span>
</div>
</div>
`;
import Vue from 'vue';
import { removeBreakLine } from 'helpers/text_helper';
import { shallowMount } from '@vue/test-utils';
import PipelineFailed from '~/vue_merge_request_widget/components/states/pipeline_failed.vue';
import statusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
describe('PipelineFailed', () => {
describe('template', () => {
const Component = Vue.extend(PipelineFailed);
const vm = new Component({
el: document.createElement('div'),
});
it('should have correct elements', () => {
expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy();
expect(removeBreakLine(vm.$el.innerText).trim()).toContain(
'The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure',
);
});
let wrapper;
const createComponent = () => {
wrapper = shallowMount(PipelineFailed);
};
const findStatusIcon = () => wrapper.find(statusIcon);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('should render error message with a disabled merge button', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('merge button should be disabled', () => {
expect(findStatusIcon().props('showDisabledButton')).toBe(true);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment