Commit da018269 authored by David O'Regan's avatar David O'Regan Committed by Peter Leitzen

Moving alerts endpoint configuration

We move the alerts endpoint config to settings >
operations to ensure users gain a consistant
experience.
parent 9baace02
......@@ -64,6 +64,11 @@ export default {
type: Boolean,
required: true,
},
isDisabled: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
......@@ -118,6 +123,9 @@ export default {
.then(() => {
this.activated = value;
this.loadingActivated = false;
if (value) {
window.location.reload();
}
})
.catch(() => {
createFlash(__('Update failed. Please try again.'));
......@@ -142,7 +150,7 @@ export default {
<gl-form-group :label="__('Active')" label-for="activated" label-class="label-bold">
<toggle-button
id="activated"
:disabled-input="loadingActivated"
:disabled-input="loadingActivated || isDisabled"
:is-loading="loadingActivated"
:value="activated"
@change="toggleActivated"
......@@ -152,7 +160,11 @@ export default {
<div class="input-group">
<gl-form-input id="url" :readonly="true" :value="url" />
<span class="input-group-append">
<clipboard-button :text="url" :title="$options.COPY_TO_CLIPBOARD" />
<clipboard-button
:text="url"
:title="$options.COPY_TO_CLIPBOARD"
:disabled="isDisabled"
/>
</span>
</div>
</gl-form-group>
......@@ -164,10 +176,16 @@ export default {
<div class="input-group">
<gl-form-input id="authorization-key" :readonly="true" :value="authorizationKey" />
<span class="input-group-append">
<clipboard-button :text="authorizationKey" :title="$options.COPY_TO_CLIPBOARD" />
<clipboard-button
:text="authorizationKey"
:title="$options.COPY_TO_CLIPBOARD"
:disabled="isDisabled"
/>
</span>
</div>
<gl-button v-gl-modal.authKeyModal class="mt-2">{{ $options.RESET_KEY }}</gl-button>
<gl-button v-gl-modal.authKeyModal class="mt-2" :disabled="isDisabled">{{
$options.RESET_KEY
}}</gl-button>
<gl-modal
modal-id="authKeyModal"
:title="$options.RESET_KEY"
......
......@@ -14,8 +14,11 @@ export default el => {
formPath,
authorizationKey,
url,
disabled,
} = el.dataset;
const activated = parseBoolean(activatedStr);
const isDisabled = parseBoolean(disabled);
return new Vue({
el,
......@@ -28,6 +31,7 @@ export default el => {
formPath,
initialAuthorizationKey: authorizationKey,
url,
isDisabled,
},
});
},
......
import mountErrorTrackingForm from '~/error_tracking_settings';
import initAlertsSettings from '~/alerts_service_settings';
import mountOperationSettings from '~/operation_settings';
import mountGrafanaIntegration from '~/grafana_integration';
import initSettingsPanels from '~/settings_panels';
......@@ -10,4 +11,5 @@ document.addEventListener('DOMContentLoaded', () => {
if (!IS_EE) {
initSettingsPanels();
}
initAlertsSettings(document.querySelector('.js-alerts-service-settings'));
});
......@@ -5,6 +5,7 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-users-over-license-callout',
'.js-admin-licensed-user-count-threshold',
'.js-buy-pipeline-minutes-notification-callout',
'.js-alerts-moved-alert',
];
const initCallouts = () => {
......
......@@ -11,7 +11,7 @@ module Projects
helper_method :error_tracking_setting
def show
render locals: { prometheus_service: prometheus_service }
render locals: { prometheus_service: prometheus_service, alerts_service: alerts_service }
end
def update
......@@ -52,6 +52,10 @@ module Projects
project.find_or_initialize_service(::PrometheusService.to_param)
end
def alerts_service
project.find_or_initialize_service(::AlertsService.to_param)
end
def render_update_response(result)
respond_to do |format|
format.html do
......
......@@ -7,6 +7,7 @@ module UserCalloutsHelper
SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed'
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
ALERTS_MOVED = 'alerts_moved'
def show_admin_integrations_moved?
!user_dismissed?(ADMIN_INTEGRATIONS_MOVED)
......@@ -43,6 +44,10 @@ module UserCalloutsHelper
!user_dismissed?(WEBHOOKS_MOVED)
end
def show_alerts_moved_alert?
!user_dismissed?(ALERTS_MOVED)
end
private
def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil)
......
......@@ -17,7 +17,8 @@ module UserCalloutEnums
suggest_popover_dismissed: 9,
tabs_position_highlight: 10,
webhooks_moved: 13,
admin_integrations_moved: 15
admin_integrations_moved: 15,
alerts_moved: 20
}
end
end
......
- if lookup_context.template_exists?('top', "projects/services/#{@service.to_param}", true)
= render "projects/services/#{@service.to_param}/top"
.row.gl-mt-3.gl-mb-3
.col-lg-4
%h4.gl-mt-0
......@@ -12,7 +15,7 @@
.col-lg-8
= form_for(@service, as: :service, url: scoped_integration_path(@service), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, integration: @service
.footer-block.row-content-block
.footer-block.row-content-block{ :class => "#{'gl-display-none' if @service.is_a?(AlertsService)}" }
%input{ id: 'services_redirect_to', type: 'hidden', name: 'redirect_to', value: request.referrer }
= service_save_button
&nbsp;
......
......@@ -2,5 +2,6 @@
form_path: scoped_integration_path(@service),
authorization_key: @service.token,
url: @service.url || _('<namespace / project>'),
disabled: 'true',
alerts_setup_url: help_page_path('user/project/integrations/generic_alerts.html', anchor: 'setting-up-generic-alerts'),
alerts_usage_url: help_page_path('user/project/operations/alert_management.html') } }
- return unless show_alerts_moved_alert?
.row
.col-lg-12
.gl-alert.gl-alert-info.js-alerts-moved-alert{ role: 'alert', data: { feature_id: UserCalloutsHelper::ALERTS_MOVED, dismiss_endpoint: user_callouts_path } }
= sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
%button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss') }
= sprite_icon('close', size: 16, css_class: 'gl-icon')
.gl-alert-body
= _('You can now manage alert endpoint configuration in the Alerts section on the Operations settings page. Fields on this page have been deprecated.')
.gl-alert-actions
= link_to _('Visit settings page'), project_settings_operations_path(@project), class: 'btn gl-alert-action btn-info new-gl-button'
- return unless can?(current_user, :admin_operations, @project)
%section.settings.no-animate.js-alert-management-settings
.settings-header
%h3{ :class => "h4" }
= _('Alerts')
%button.btn.js-settings-toggle{ type: 'button' }
= _('Expand')
%p
= _('Display alerts from all your monitoring tools directly within GitLab.')
= link_to _('More information'), help_page_path('user/project/operations/alert_management'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
.js-alerts-service-settings{ data: { activated: service.activated?.to_s,
form_path: scoped_integration_path(service),
authorization_key: service.token,
url: service.url || _('<namespace / project>'),
alerts_setup_url: help_page_path('user/project/integrations/generic_alerts.html', anchor: 'setting-up-generic-alerts'),
alerts_usage_url: project_alert_management_index_path(@project) } }
......@@ -2,6 +2,7 @@
- page_title _('Operations Settings')
- breadcrumb_title _('Operations Settings')
= render 'projects/settings/operations/alert_management', service: alerts_service
= render 'projects/settings/operations/incidents'
= render 'projects/settings/operations/error_tracking'
= render 'projects/settings/operations/prometheus', service: prometheus_service if Feature.enabled?(:settings_operations_prometheus_service)
......
---
title: Move configuration for Alerts endpoint from "Settings > Integration" to "Settings > Operations > Alerts"
merge_request: 35187
author:
type: other
......@@ -3,8 +3,15 @@
require 'spec_helper'
RSpec.describe 'projects/settings/operations/show' do
let(:project) { create(:project, :repository) }
let(:error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
let_it_be(:project, refind: true) { create(:project, :repository) }
let_it_be(:error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
let(:operations_show_locals) do
{
prometheus_service: project.find_or_initialize_service('prometheus'),
alerts_service: project.find_or_initialize_service('alerts')
}
end
before do
assign(:project, project)
......@@ -26,7 +33,7 @@ RSpec.describe 'projects/settings/operations/show' do
end
it 'links to project.tracing_external_url' do
render template: "projects/settings/operations/show", locals: { prometheus_service: project.find_or_initialize_service('prometheus') }
render template: 'projects/settings/operations/show', locals: operations_show_locals
expect(rendered).to have_link('Tracing', href: tracing_url)
end
......@@ -40,7 +47,7 @@ RSpec.describe 'projects/settings/operations/show' do
end
it 'sanitizes external_url' do
render template: "projects/settings/operations/show", locals: { prometheus_service: project.find_or_initialize_service('prometheus') }
render template: 'projects/settings/operations/show', locals: operations_show_locals
expect(tracing_setting.external_url).to eq(malicious_tracing_url)
expect(rendered).to have_link('Tracing', href: cleaned_url)
......@@ -59,7 +66,7 @@ RSpec.describe 'projects/settings/operations/show' do
end
it 'links to Tracing page' do
render template: "projects/settings/operations/show", locals: { prometheus_service: project.find_or_initialize_service('prometheus') }
render template: 'projects/settings/operations/show', locals: operations_show_locals
expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
......
......@@ -8009,6 +8009,9 @@ msgstr ""
msgid "Dismissed on pipeline %{pipelineLink} at %{projectLink}"
msgstr ""
msgid "Display alerts from all your monitoring tools directly within GitLab."
msgstr ""
msgid "Display name"
msgstr ""
......@@ -25389,6 +25392,9 @@ msgstr ""
msgid "VisibilityLevel|Unknown"
msgstr ""
msgid "Visit settings page"
msgstr ""
msgid "VisualReviewApp|%{stepStart}Step 1%{stepEnd}. Copy the following script:"
msgstr ""
......@@ -26111,6 +26117,9 @@ msgstr ""
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
msgid "You can now manage alert endpoint configuration in the Alerts section on the Operations settings page. Fields on this page have been deprecated."
msgstr ""
msgid "You can now submit a merge request to get this change into the original branch."
msgstr ""
......
......@@ -15,35 +15,32 @@ RSpec.describe 'User activates Alerts', :js do
end
context 'when service is deactivated' do
it 'activates service' do
it 'user cannot activate service' do
visit_project_services
expect(page).to have_link(service_title)
click_link(service_title)
expect(page).to have_callout_message
expect(page).not_to have_active_service
click_activate_service
wait_for_requests
expect(page).to have_active_service
expect(page).to have_toggle_active_disabled
end
end
context 'when service is activated' do
let_it_be(:activated_alerts_service) do
create(:alerts_service, :active, project: project)
end
before do
visit_alerts_service
click_activate_service
end
it 're-generates key' do
expect(reset_key.value).to be_blank
click_reset_key
click_confirm_reset_key
wait_for_requests
expect(reset_key.value).to be_present
it 'user cannot change settings' do
expect(page).to have_callout_message
expect(page).to have_active_service
expect(page).to have_toggle_active_disabled
expect(page).to have_button_reset_key_disabled
end
end
......@@ -57,25 +54,21 @@ RSpec.describe 'User activates Alerts', :js do
visit(edit_project_service_path(project, service_name))
end
def click_activate_service
find('#activated').click
end
def click_reset_key
click_button('Reset key')
def have_callout_message
within('.gl-alert') do
have_content('You can now manage alert endpoint configuration in the Alerts section on the Operations settings page.')
end
end
def click_confirm_reset_key
within '.modal-content' do
click_reset_key
end
def have_active_service
have_selector('.js-service-active-status[data-value="true"]')
end
def reset_key
find_field('Authorization key')
def have_toggle_active_disabled
have_selector('#activated .project-feature-toggle.is-disabled')
end
def have_active_service
have_selector('.js-service-active-status[data-value="true"]')
def have_button_reset_key_disabled
have_button('Reset key', disabled: true)
end
end
......@@ -15,6 +15,7 @@ const defaultProps = {
alertsSetupUrl: 'http://invalid',
alertsUsageUrl: 'http://invalid',
initialActivated: false,
isDisabled: false,
};
describe('AlertsServiceForm', () => {
......@@ -166,4 +167,17 @@ describe('AlertsServiceForm', () => {
});
});
});
describe('form is disabled', () => {
beforeEach(() => {
createComponent({ isDisabled: true });
});
it('cannot be toggled', () => {
wrapper.find(ToggleButton).vm.$emit('change');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.find(ToggleButton).props('disabledInput')).toBe(true);
});
});
});
});
......@@ -3,14 +3,14 @@
require "spec_helper"
RSpec.describe UserCalloutsHelper do
let(:user) { create(:user) }
let_it_be(:user) { create(:user) }
before do
allow(helper).to receive(:current_user).and_return(user)
end
describe '.show_gke_cluster_integration_callout?' do
let(:project) { create(:project) }
let_it_be(:project) { create(:project) }
subject { helper.show_gke_cluster_integration_callout?(project) }
......@@ -67,6 +67,26 @@ RSpec.describe UserCalloutsHelper do
end
end
describe '.show_alerts_moved_alert?' do
subject { helper.show_alerts_moved_alert? }
context 'when user has not dismissed' do
before do
allow(helper).to receive(:user_dismissed?).with(described_class::ALERTS_MOVED) { false }
end
it { is_expected.to be true }
end
context 'when user dismissed' do
before do
allow(helper).to receive(:user_dismissed?).with(described_class::ALERTS_MOVED) { 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)
......
......@@ -3,8 +3,15 @@
require 'spec_helper'
RSpec.describe 'projects/settings/operations/show' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let(:operations_show_locals) do
{
prometheus_service: project.find_or_initialize_service('prometheus'),
alerts_service: project.find_or_initialize_service('alerts')
}
end
before do
assign :project, project
......@@ -20,13 +27,13 @@ RSpec.describe 'projects/settings/operations/show' do
allow(view).to receive(:incident_management_available?) { false }
end
let!(:error_tracking_setting) do
let_it_be(:error_tracking_setting) do
create(:project_error_tracking_setting, project: project)
end
context 'Settings page ' do
it 'renders the Operations Settings page' do
render template: "projects/settings/operations/show", locals: { prometheus_service: project.find_or_initialize_service('prometheus') }
render template: 'projects/settings/operations/show', locals: operations_show_locals
expect(rendered).to have_content _('Error Tracking')
expect(rendered).to have_content _('To link Sentry to GitLab, enter your Sentry URL and Auth Token')
......
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