Commit c4fec8cd authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '196525-admin-area-add-instance-level-integration-settings-ui' into 'master'

Add Instance-Level Integration Settings UI

See merge request gitlab-org/gitlab!25752
parents dba282b5 b5bb6c46
import PersistentUserCallout from '~/persistent_user_callout';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.js-admin-integrations-moved');
PersistentUserCallout.factory(callout);
});
......@@ -81,3 +81,8 @@
.gl-text-green-700 { @include gl-text-green-700; }
.gl-align-items-center { @include gl-align-items-center; }
.d-sm-table-column {
@include media-breakpoint-up(sm) {
display: table-column !important;
}
}
......@@ -27,6 +27,16 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
define_method(action) { perform_update if submitted? }
end
def integrations
if Feature.enabled?(:instance_level_integrations)
# TODO: Update this with actual integrations
# To be fixed with https://gitlab.com/gitlab-org/gitlab/-/issues/199388
@integrations = []
end
perform_update if submitted?
end
def update
perform_update
end
......
......@@ -62,6 +62,10 @@ module ServicesHelper
!current_controller?("admin/services") && service.deprecated?
end
def edit_integration_path(integration)
edit_admin_application_settings_integration_path(integration)
end
extend self
end
......
# frozen_string_literal: true
module UserCalloutsHelper
ADMIN_INTEGRATIONS_MOVED = 'admin_integrations_moved'
GKE_CLUSTER_INTEGRATION = 'gke_cluster_integration'
GCP_SIGNUP_OFFER = 'gcp_signup_offer'
SUGGEST_POPOVER_DISMISSED = 'suggest_popover_dismissed'
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
def show_admin_integrations_moved?
!user_dismissed?(ADMIN_INTEGRATIONS_MOVED)
end
def show_gke_cluster_integration_callout?(project)
can?(current_user, :create_cluster, project) &&
!user_dismissed?(GKE_CLUSTER_INTEGRATION)
......
......@@ -16,7 +16,8 @@ module UserCalloutEnums
cluster_security_warning: 3,
suggest_popover_dismissed: 9,
tabs_position_highlight: 10,
webhooks_moved: 13
webhooks_moved: 13,
admin_integrations_moved: 15
}
end
end
......
......@@ -103,3 +103,12 @@
= s_('IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox client side evaluation.')
= f.submit _('Save changes'), class: "btn btn-success"
- if Feature.enabled?(:instance_level_integrations)
= render_if_exists 'admin/application_settings/elasticsearch_form'
= render 'admin/application_settings/plantuml'
= render 'admin/application_settings/sourcegraph'
= render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow'
= render 'admin/application_settings/eks'
- breadcrumb_title _("Integrations")
- page_title _("Integrations")
- @content_class = "limit-container-width" unless fluid_layout
- breadcrumb_title _('Integrations')
- page_title _('Integrations')
- @content_class = 'limit-container-width' unless fluid_layout
= render_if_exists 'admin/application_settings/elasticsearch_form'
= render 'admin/application_settings/plantuml'
= render 'admin/application_settings/sourcegraph'
= render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow'
= render 'admin/application_settings/eks'
- if Feature.enabled?(:instance_level_integrations)
- if show_admin_integrations_moved?
.gl-alert.gl-alert-info.js-admin-integrations-moved.mt-3{ role: 'alert', data: { feature_id: UserCalloutsHelper::ADMIN_INTEGRATIONS_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
%h4.gl-alert-title= s_('AdminSettings|Some settings have moved')
= s_('AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General.')
.gl-alert-actions
= link_to s_('AdminSettings|Go to General Settings'), admin_application_settings_path, class: 'btn gl-alert-action btn-info new-gl-button'
%h4= s_('AdminSettings|Apply integration settings to all Projects')
%p
= s_('AdminSettings|Integrations configured here will automatically apply to all projects on this instance.')
= link_to _('Learn more'), '#'
= render 'projects/services/integrations'
- else
= render_if_exists 'admin/application_settings/elasticsearch_form'
= render 'admin/application_settings/plantuml'
= render 'admin/application_settings/sourcegraph'
= render_if_exists 'admin/application_settings/slack'
= render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow'
= render 'admin/application_settings/eks'
- add_to_breadcrumbs _('Integrations'), admin_application_settings_integration_path
- add_to_breadcrumbs _('Integrations'), integrations_admin_application_settings_path
- breadcrumb_title @service.title
- page_title @service.title, _('Integrations')
......
%table.table.b-table.gl-table.mt-3{ role: 'table', 'aria-busy': false, 'aria-colcount': 4 }
%colgroup
%col
%col
%col.d-none.d-sm-table-column
%col{ width: 120 }
%thead{ role: 'rowgroup' }
%tr{ role: 'row' }
%th{ role: 'columnheader', scope: 'col', 'aria-colindex': 1 }
%th{ role: 'columnheader', scope: 'col', 'aria-colindex': 2 }= _('Integration')
%th.d-none.d-sm-block{ role: 'columnheader', scope: 'col', 'aria-colindex': 3 }= _('Description')
%th{ role: 'columnheader', scope: 'col', 'aria-colindex': 4 }= _('Last updated')
%tbody{ role: 'rowgroup' }
- @integrations&.each do |integration|
%tr{ role: 'row' }
%td{ role: 'cell', 'aria-colindex': 1 }
= boolean_to_icon integration.activated?
%td{ role: 'cell', 'aria-colindex': 2 }
= link_to edit_integration_path(integration) do
%strong= integration.title
%td.d-none.d-sm-block{ role: 'cell', 'aria-colindex': 3 }
= integration.description
%td{ role: 'cell', 'aria-colindex': 4 }
- if integration.updated_at.present?
= time_ago_with_tooltip integration.updated_at
......@@ -2,6 +2,77 @@ import '~/pages/admin/application_settings/index';
import groupsSelect from '~/groups_select';
import 'select2/select2';
import $ from 'jquery';
import { s__ } from '~/locale';
import Api from '~/api';
const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => {
$limitByNamespaces.find('.select2').select2('data', null);
$limitByNamespaces.find('.select2').select2('data', null);
$limitByNamespaces.toggleClass('hidden', !checked);
$limitByProjects.toggleClass('hidden', !checked);
};
const getDropdownConfig = (placeholder, apiPath, textProp) => ({
placeholder,
multiple: true,
initSelection($el, callback) {
callback($el.data('selected'));
},
ajax: {
url: Api.buildUrl(apiPath),
dataType: 'JSON',
quietMillis: 250,
data(search) {
return {
search,
};
},
results(data) {
return {
results: data.map(entity => ({
id: entity.id,
text: entity[textProp],
})),
};
},
},
});
document.addEventListener('DOMContentLoaded', () => {
groupsSelect();
// ElasticSearch
const $container = $('#js-elasticsearch-settings');
$container
.find('.js-limit-checkbox')
.on('change', e =>
onLimitCheckboxChange(
e.currentTarget.checked,
$container.find('.js-limit-namespaces'),
$container.find('.js-limit-projects'),
),
);
$container
.find('.js-elasticsearch-namespaces')
.select2(
getDropdownConfig(
s__('Elastic|None. Select namespaces to index.'),
Api.namespacesPath,
'full_path',
),
);
$container
.find('.js-elasticsearch-projects')
.select2(
getDropdownConfig(
s__('Elastic|None. Select projects to index.'),
Api.projectsPath,
'name_with_namespace',
),
);
});
......@@ -2,6 +2,7 @@ import 'select2/select2';
import $ from 'jquery';
import { s__ } from '~/locale';
import Api from '~/api';
import PersistentUserCallout from '~/persistent_user_callout';
const onLimitCheckboxChange = (checked, $limitByNamespaces, $limitByProjects) => {
$limitByNamespaces.find('.select2').select2('data', null);
......@@ -37,6 +38,10 @@ const getDropdownConfig = (placeholder, apiPath, textProp) => ({
});
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.js-admin-integrations-moved');
PersistentUserCallout.factory(callout);
// ElasticSearch
const $container = $('#js-elasticsearch-settings');
$container
......
......@@ -57,7 +57,7 @@ describe 'Admin updates EE-only settings' do
context 'Elasticsearch settings' do
before do
visit integrations_admin_application_settings_path
visit general_admin_application_settings_path
page.within('.as-elasticsearch') do
click_button 'Expand'
end
......@@ -137,7 +137,7 @@ describe 'Admin updates EE-only settings' do
namespace = create(:elasticsearch_indexed_namespace).namespace
project = create(:elasticsearch_indexed_project).project
visit integrations_admin_application_settings_path
visit general_admin_application_settings_path
expect(ElasticsearchIndexedNamespace.count).to be > 0
expect(ElasticsearchIndexedProject.count).to be > 0
......@@ -166,9 +166,8 @@ describe 'Admin updates EE-only settings' do
end
it 'Enable Slack application' do
visit integrations_admin_application_settings_path
allow(Gitlab).to receive(:com?).and_return(true)
visit integrations_admin_application_settings_path
visit general_admin_application_settings_path
page.within('.as-slack') do
check 'Enable Slack application'
......
......@@ -1346,15 +1346,27 @@ msgstr ""
msgid "AdminProjects|Delete project"
msgstr ""
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
msgid "AdminSettings|Auto DevOps domain"
msgstr ""
msgid "AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General."
msgstr ""
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
msgid "AdminSettings|Environment variables are protected by default"
msgstr ""
msgid "AdminSettings|Go to General Settings"
msgstr ""
msgid "AdminSettings|Integrations configured here will automatically apply to all projects on this instance."
msgstr ""
msgid "AdminSettings|No required pipeline"
msgstr ""
......@@ -1370,6 +1382,9 @@ msgstr ""
msgid "AdminSettings|Set an instance-wide auto included %{link_start}pipeline configuration%{link_end}. This pipeline configuration will be run after the project's own configuration."
msgstr ""
msgid "AdminSettings|Some settings have moved"
msgstr ""
msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
msgstr ""
......@@ -10943,6 +10958,9 @@ msgstr ""
msgid "Instance license"
msgstr ""
msgid "Integration"
msgstr ""
msgid "Integration Settings"
msgstr ""
......
......@@ -3,5 +3,6 @@
FactoryBot.define do
factory :application_setting do
default_projects_limit { 42 }
import_sources { [] }
end
end
......@@ -194,12 +194,6 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_content "Application settings saved successfully"
expect(current_settings.terminal_max_session_time).to eq(15)
end
end
context 'Integrations page' do
before do
visit integrations_admin_application_settings_path
end
it 'Enable hiding third party offers' do
page.within('.as-third-party-offers') do
......@@ -241,6 +235,25 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
end
end
context 'Integration page', :js do
before do
visit integrations_admin_application_settings_path
end
it 'allows user to dismiss deprecation notice' do
expect(page).to have_content('Some settings have moved')
click_button 'Dismiss'
wait_for_requests
expect(page).not_to have_content('Some settings have moved')
visit integrations_admin_application_settings_path
expect(page).not_to have_content('Some settings have moved')
end
end
context 'CI/CD page' do
it 'Change CI/CD settings' do
visit ci_cd_admin_application_settings_path
......
......@@ -208,7 +208,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
visit integrations_admin_application_settings_path
visit general_admin_application_settings_path
end
it 'user does not see the offer' do
......
......@@ -47,6 +47,26 @@ describe UserCalloutsHelper do
end
end
describe '.show_admin_integrations_moved?' do
subject { helper.show_admin_integrations_moved? }
context 'when user has not dismissed' do
before do
allow(helper).to receive(:user_dismissed?).with(described_class::ADMIN_INTEGRATIONS_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::ADMIN_INTEGRATIONS_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)
......
......@@ -2,8 +2,9 @@
require 'spec_helper'
describe 'admin/application_settings/integrations.html.haml' do
describe 'admin/application_settings/general.html.haml' do
let(:app_settings) { build(:application_setting) }
let(:user) { create(:admin) }
describe 'sourcegraph integration' do
let(:sourcegraph_flag) { true }
......@@ -11,6 +12,7 @@ describe 'admin/application_settings/integrations.html.haml' do
before do
assign(:application_setting, app_settings)
allow(Gitlab::Sourcegraph).to receive(:feature_available?).and_return(sourcegraph_flag)
allow(view).to receive(:current_user).and_return(user)
end
context 'when sourcegraph feature is enabled' do
......
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