Commit bca413ab authored by Paul Slaughter's avatar Paul Slaughter

Merge branch...

Merge branch '12155-update-pipelines-minutes-expiry-banner-to-an-alert-component-type' into 'master'

Resolve "Update Pipelines Minutes expiry banner to Alert Component"

Closes #12156 and #12155

See merge request gitlab-org/gitlab-ee!14786
parents 38cd0daf f651043d
......@@ -83,6 +83,11 @@ export default {
type: String,
required: true,
},
subscriptionsMoreMinutesUrl: {
type: String,
required: false,
default: null,
},
},
computed: {
...mapState([
......@@ -265,6 +270,7 @@ export default {
:quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl"
:project-path="projectPath"
:subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
/>
<environments-block
......
......@@ -15,6 +15,7 @@ export default () => {
runnerHelpUrl,
runnerSettingsUrl,
variablesSettingsUrl,
subscriptionsMoreMinutesUrl,
endpoint,
pagePath,
logState,
......@@ -28,6 +29,7 @@ export default () => {
runnerHelpUrl,
runnerSettingsUrl,
variablesSettingsUrl,
subscriptionsMoreMinutesUrl,
endpoint,
pagePath,
logState,
......
......@@ -73,13 +73,6 @@ export default class Project {
.remove();
return e.preventDefault();
});
$('.hide-shared-runner-limit-message').on('click', function(e) {
var $alert = $(this).parents('.shared-runner-quota-message');
var scope = $alert.data('scope');
Cookies.set('hide_shared_runner_quota_message', 'false', { path: scope });
$alert.remove();
e.preventDefault();
});
$('.hide-auto-devops-implicitly-enabled-banner').on('click', function(e) {
const projectId = $(this).data('project-id');
const cookieKey = `hide_auto_devops_implicitly_enabled_banner_${projectId}`;
......
# frozen_string_literal: true
module JobsHelper
def jobs_data
{
"endpoint" => project_job_path(@project, @build, format: :json),
"project_path" => @project.full_path,
"deployment_help_url" => help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
"runner_help_url" => help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
"runner_settings_url" => project_runners_path(@build.project, anchor: 'js-runners-settings'),
"variables_settings_url" => project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
"page_path" => project_job_path(@project, @build),
"build_status" => @build.status,
"build_stage" => @build.stage,
"log_state" => '',
"build_options" => javascript_build_options
}
end
end
......@@ -5,10 +5,4 @@
- content_for :page_specific_javascripts do
= stylesheet_link_tag 'page_bundles/xterm'
#js-job-vue-app{ data: { endpoint: project_job_path(@project, @build, format: :json), project_path: @project.full_path,
deployment_help_url: help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings'),
variables_settings_url: project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
page_path: project_job_path(@project, @build), build_status: @build.status, build_stage: @build.stage, log_state: '',
build_options: javascript_build_options } }
#js-job-vue-app{ data: jobs_data }
<script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlButton } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
export default {
components: {
GlButton,
},
props: {
quotaUsed: {
type: Number,
......@@ -15,19 +20,48 @@ export default {
required: false,
default: null,
},
projectPath: {
type: String,
required: true,
},
subscriptionsMoreMinutesUrl: {
type: String,
required: false,
default: null,
},
},
computed: {
isExpired() {
return this.artifact.expired;
},
runnersWarningMessage() {
return sprintf(
s__(
'Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes.',
),
{ quotaUsed: this.quotaUsed, quotaLimit: this.quotaLimit },
);
},
},
};
</script>
<template>
<div class="bs-callout bs-callout-warning">
<div class="bs-callout bs-callout-danger">
<p>
{{ s__('Runners|You have used all your shared Runners pipeline minutes.') }}
{{ quotaUsed }} of {{ quotaLimit }}
{{ runnersWarningMessage }}
<template v-if="runnersPath">
{{ __('For more information, go to the ') }}
<a :href="runnersPath"> {{ __('Runners page.') }} </a>
<a :href="runnersPath">{{ __('Runners page.') }}</a>
</template>
</p>
<gl-button
v-if="subscriptionsMoreMinutesUrl"
variant="danger"
:href="subscriptionsMoreMinutesUrl"
class="btn-inverted"
>
{{ __('Purchase more minutes') }}
</gl-button>
</div>
</template>
# frozen_string_literal: true
module EE
module JobsHelper
extend ::Gitlab::Utils::Override
override :jobs_data
def jobs_data
super.merge({
"subscriptions_more_minutes_url" => ::EE::SUBSCRIPTIONS_MORE_MINUTES_URL
})
end
end
end
::JobsHelper.prepend_if_ee('::EE::JobsHelper')
......@@ -9,20 +9,12 @@ module EE
if ::Gitlab.com? && can?(current_user, :admin_project, project)
message += " #{purchase_shared_runner_minutes_link}"
elsif namespace.shared_runners_minutes_used?
message += s_('Pipelines|Pipelines will not run anymore on shared Runners.')
message += " #{s_('Pipelines|Pipelines will not run anymore on shared Runners.')}"
end
message.html_safe
end
def ci_usage_warning_class(namespace)
if EE::Namespace::CI_USAGE_ALERT_LEVELS.min == namespace.last_ci_minutes_usage_notification_level
'alert-danger'
else
'alert-warning'
end
end
private
def purchase_shared_runner_minutes_link
......
......@@ -5,9 +5,9 @@
- can_see_status = project.nil? || can?(current_user, :create_pipeline, project)
- ci_warning_message = ci_usage_warning_message(namespace, project)
- if cookies[:hide_shared_runner_quota_message].blank? && has_limit && can_see_status && ci_warning_message.present?
.shared-runner-quota-message.alert.d-none.d-sm-block{ class: ci_usage_warning_class(namespace), data: { scope: scope } }
= ci_warning_message
.float-right
= link_to 'Remind later', '#', class: 'hide-shared-runner-limit-message alert-link'
- if has_limit && can_see_status && ci_warning_message.present?
%div{ class: ["pt-2", (classes if defined? classes)] }
.bs-callout.shared-runner-quota-message.d-none.d-sm-block.bs-callout-danger{ data: { scope: scope } }
%p
= ci_warning_message
= link_to _('Purchase more minutes'), ::EE::SUBSCRIPTIONS_MORE_MINUTES_URL, class: "btn btn-danger btn-inverted"
= content_for :flash_message do
= render 'shared/shared_runners_minutes_limit', project: @project
%div{ class: container_class }
= render 'shared/shared_runners_minutes_limit', project: @project
---
title: Update Pipelines Minutes expiry banner to Alert Component
merge_request: 14786
author:
type: other
......@@ -3,4 +3,5 @@
module EE
SUBSCRIPTIONS_URL = 'https://customers.gitlab.com'.freeze
SUBSCRIPTIONS_PLANS_URL = "#{SUBSCRIPTIONS_URL}/plans".freeze
SUBSCRIPTIONS_MORE_MINUTES_URL = "#{SUBSCRIPTIONS_URL}/buy_pipeline_minutes".freeze
end
......@@ -22,7 +22,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job)
wait_for_requests
expect(page).to have_content('You have used all your shared Runners pipeline minutes.')
expect(page).to have_content('You have used 1000 out of 500 of your shared Runners pipeline minutes.')
end
end
......@@ -34,7 +34,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
visit project_job_path(project, job)
wait_for_requests
expect(page).not_to have_content('You have used all your shared Runners pipeline minutes.')
expect(page).not_to have_content('You have used 1000 out of 500 of your shared Runners pipeline minutes.')
end
end
end
......
import Vue from 'vue';
import component from 'ee/jobs/components/shared_runner_limit_block.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
import { trimText } from 'spec/helpers/text_helper';
const localVue = createLocalVue();
describe('Shared Runner Limit Block', () => {
const Component = Vue.extend(component);
let vm;
let wrapper;
const Component = localVue.extend(component);
const runnersPath = 'root/project/runners';
const projectPath = 'h5bp/html5-boilerplate';
const subscriptionsMoreMinutesUrl = 'https://customers.gitlab.com/buy_pipeline_minutes';
const factory = (options = {}) => {
wrapper = shallowMount(Component, {
localVue,
sync: false,
...options,
});
};
afterEach(() => {
vm.$destroy();
wrapper.destroy();
wrapper = null;
});
describe('quota information', () => {
it('renders provided quota limit and used quota', () => {
vm = mountComponent(Component, {
quotaUsed: 1000,
quotaLimit: 4000,
runnersPath: 'root/project/runners',
beforeEach(() => {
factory({
propsData: {
quotaUsed: 1000,
quotaLimit: 4000,
runnersPath,
projectPath,
subscriptionsMoreMinutesUrl,
},
});
});
expect(vm.$el.textContent).toContain(
'You have used all your shared Runners pipeline minutes.',
it('renders provided quota limit and used quota', () => {
expect(wrapper.text()).toContain(
'You have used 1000 out of 4000 of your shared Runners pipeline minutes',
);
});
it('renders call to action gl-button with the right href', () => {
const glButton = wrapper.find(GlButton);
expect(vm.$el.textContent).toContain('1000 of 4000');
expect(glButton.isVisible()).toBe(true);
expect(glButton.attributes('variant')).toBe('danger');
expect(glButton.attributes('href')).toBe(subscriptionsMoreMinutesUrl);
});
});
describe('with runnersPath', () => {
it('renders runner link', () => {
vm = mountComponent(Component, {
quotaUsed: 1000,
quotaLimit: 4000,
runnersPath: 'root/project/runners',
factory({
propsData: {
quotaUsed: 1000,
quotaLimit: 4000,
projectPath,
runnersPath,
subscriptionsMoreMinutesUrl,
},
});
expect(trimText(vm.$el.textContent)).toContain(
'For more information, go to the Runners page.',
);
expect(trimText(wrapper.text())).toContain('For more information, go to the Runners page.');
});
});
describe('without runnersPath', () => {
it('does not renbder runner link', () => {
vm = mountComponent(Component, {
quotaUsed: 1000,
quotaLimit: 4000,
it('does not render runner link', () => {
factory({
propsData: {
quotaUsed: 1000,
quotaLimit: 4000,
projectPath,
subscriptionsMoreMinutesUrl,
},
});
expect(trimText(vm.$el.textContent)).not.toContain(
expect(trimText(wrapper.element.textContent)).not.toContain(
'For more information, go to the Runners page.',
);
});
......
......@@ -10918,9 +10918,6 @@ msgstr ""
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|Pipelines will not run anymore on shared Runners."
msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr ""
......@@ -12307,6 +12304,9 @@ msgstr ""
msgid "Pull"
msgstr ""
msgid "Purchase more minutes"
msgstr ""
msgid "Push"
msgstr ""
......@@ -13098,7 +13098,7 @@ msgstr ""
msgid "Runners page."
msgstr ""
msgid "Runners|You have used all your shared Runners pipeline minutes."
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
msgid "Running"
......
......@@ -25,6 +25,7 @@ describe('Job App ', () => {
terminalPath: 'jobs/123/terminal',
pagePath: `${gl.TEST_HOST}jobs/123`,
projectPath: 'user-name/project-name',
subscriptionsMoreMinutesUrl: 'https://customers.gitlab.com/buy_pipeline_minutes',
logState:
'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
};
......
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