Commit 2babea36 authored by Phil Hughes's avatar Phil Hughes

Merge branch '199882-update-active-checkbox-component' into 'master'

Update Active checkbox component to use toggle

See merge request gitlab-org/gitlab!27778
parents 2f8cec33 37f9948e
<script>
import eventHub from '../event_hub';
import { GlToggle } from '@gitlab/ui';
export default {
name: 'ActiveToggle',
components: {
GlToggle,
},
props: {
initialActivated: {
type: Boolean,
required: true,
},
disabled: {
type: Boolean,
required: true,
},
},
data() {
return {
activated: this.initialActivated,
};
},
mounted() {
// Initialize view
this.$nextTick(() => {
this.onToggle(this.activated);
});
},
methods: {
onToggle(e) {
eventHub.$emit('toggle', e);
},
},
};
</script>
<template>
<div>
<div class="form-group row" role="group">
<label for="service[active]" class="col-form-label col-sm-2">{{ __('Active') }}</label>
<div class="col-sm-10 pt-1">
<gl-toggle
v-model="activated"
:disabled="disabled"
name="service[active]"
@change="onToggle"
/>
</div>
</div>
</div>
</template>
import Vue from 'vue';
export default new Vue();
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import ActiveToggle from './components/active_toggle.vue';
export default el => {
if (!el) {
return null;
}
const { showActive: showActiveStr, activated: activatedStr, disabled: disabledStr } = el.dataset;
const showActive = parseBoolean(showActiveStr);
const activated = parseBoolean(activatedStr);
const disabled = parseBoolean(disabledStr);
if (!showActive) {
return null;
}
return new Vue({
el,
render(createElement) {
return createElement(ActiveToggle, {
props: {
initialActivated: activated,
disabled,
},
});
},
});
};
......@@ -2,28 +2,33 @@ import $ from 'jquery';
import axios from '../lib/utils/axios_utils';
import flash from '../flash';
import { __ } from '~/locale';
import initForm from './edit';
import eventHub from './edit/event_hub';
export default class IntegrationSettingsForm {
constructor(formSelector) {
this.$form = $(formSelector);
this.formActive = false;
// Form Metadata
this.canTestService = this.$form.data('canTest');
this.testEndPoint = this.$form.data('testUrl');
// Form Child Elements
this.$serviceToggle = this.$form.find('#service_active');
this.$submitBtn = this.$form.find('button[type="submit"]');
this.$submitBtnLoader = this.$submitBtn.find('.js-btn-spinner');
this.$submitBtnLabel = this.$submitBtn.find('.js-btn-label');
}
init() {
// Initialize View
this.toggleServiceState(this.$serviceToggle.is(':checked'));
// Init Vue component
initForm(document.querySelector('.js-vue-integration-settings'));
eventHub.$on('toggle', active => {
this.formActive = active;
this.handleServiceToggle();
});
// Bind Event Listeners
this.$serviceToggle.on('change', e => this.handleServiceToggle(e));
this.$submitBtn.on('click', e => this.handleSettingsSave(e));
}
......@@ -31,7 +36,7 @@ export default class IntegrationSettingsForm {
// Check if Service is marked active, as if not marked active,
// We can skip testing it and directly go ahead to allow form to
// be submitted
if (!this.$serviceToggle.is(':checked')) {
if (!this.formActive) {
return;
}
......@@ -47,16 +52,16 @@ export default class IntegrationSettingsForm {
}
}
handleServiceToggle(e) {
this.toggleServiceState($(e.currentTarget).is(':checked'));
handleServiceToggle() {
this.toggleServiceState();
}
/**
* Change Form's validation enforcement based on service status (active/inactive)
*/
toggleServiceState(serviceActive) {
this.toggleSubmitBtnLabel(serviceActive);
if (serviceActive) {
toggleServiceState() {
this.toggleSubmitBtnLabel();
if (this.formActive) {
this.$form.removeAttr('novalidate');
} else if (!this.$form.attr('novalidate')) {
this.$form.attr('novalidate', 'novalidate');
......@@ -66,10 +71,10 @@ export default class IntegrationSettingsForm {
/**
* Toggle Submit button label based on Integration status and ability to test service
*/
toggleSubmitBtnLabel(serviceActive) {
toggleSubmitBtnLabel() {
let btnLabel = __('Save changes');
if (serviceActive && this.canTestService) {
if (this.formActive && this.canTestService) {
btnLabel = __('Test settings and save changes');
}
......
......@@ -8,11 +8,7 @@
= markdown @service.help
.service-settings
- if @service.show_active_box?
.form-group.row
= form.label :active, "Active", class: "col-form-label col-sm-2"
.col-sm-10
= form.check_box :active, checked: @service.active || @service.new_record?, disabled: disable_fields_service?(@service)
.js-vue-integration-settings{ data: { show_active: @service.show_active_box?.to_s, activated: (@service.active || @service.new_record?).to_s, disabled: disable_fields_service?(@service).to_s } }
- if @service.configurable_events.present?
.form-group.row
......
---
title: Update Active checkbox component to use toggle
merge_request: 27778
author:
type: added
......@@ -39,7 +39,7 @@ service in GitLab.
1. Navigate to the project you want to configure to trigger builds.
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
1. Click 'Atlassian Bamboo CI'
1. Select the 'Active' checkbox.
1. Ensure that the **Active** toggle is enabled.
1. Enter the base URL of your Bamboo server. `https://bamboo.example.com`
1. Enter the build key from your Bamboo build plan. Build keys are typically made
up from the Project Key and Plan Key that are set on project/plan creation and
......
......@@ -21,7 +21,7 @@ With the webhook URL created in the Discord channel, you can set up the Discord
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings. That is, **Project > Settings > Integrations**.
1. Select the **Discord Notifications** integration to configure it.
1. Check the **Active** checkbox to turn on the service.
1. Ensure that the **Active** toggle is enabled.
1. Check the checkboxes corresponding to the GitLab events for which you want to send notifications to Discord.
1. Paste the webhook URL that you copied from the create Discord webhook step.
1. Configure the remaining options and click the **Save changes** button.
......
......@@ -18,7 +18,7 @@ To set up the generic alerts integration:
1. Navigate to **Settings > Integrations** in a project.
1. Click on **Alerts endpoint**.
1. Toggle the **Active** alert setting. The `URL` and `Authorization Key` for the webhook configuration can be found there.
1. Toggle the **Active** alert setting. The `URL` and `Authorization Key` for the webhook configuration can be found there.
## Customizing the payload
......
......@@ -27,7 +27,7 @@ with `repo:status` access granted:
1. Navigate to the project you want to configure.
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
1. Click "GitHub".
1. Select the "Active" checkbox.
1. Ensure that the **Active** toggle is enabled.
1. Paste the token you've generated on GitHub
1. Enter the path to your project on GitHub, such as `https://github.com/username/repository`
1. Optionally uncheck **Static status check names** checkbox to disable static status check names.
......
......@@ -19,7 +19,7 @@ When you have the **Webhook URL** for your Hangouts Chat room webhook, you can s
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
1. Select the **Hangouts Chat** integration to configure it.
1. Check the **Active** checkbox to turn on the service.
1. Ensure that the **Active** toggle is enabled.
1. Check the checkboxes corresponding to the GitLab events you want to receive.
1. Paste the **Webhook URL** that you copied from the Hangouts Chat configuration step.
1. Configure the remaining options and click `Save changes`.
......
......@@ -37,7 +37,7 @@ service in GitLab.
1. Navigate to the project you want to configure for notifications.
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
1. Click "HipChat".
1. Select the "Active" checkbox.
1. Ensure that the **Active** toggle is enabled.
1. Insert the `token` field from the URL into the `Token` field on the Web page.
1. Insert the `room` field from the URL into the `Room` field on the Web page.
1. Save or optionally click "Test Settings".
......
......@@ -28,7 +28,7 @@ need to follow the firsts steps of the next section.
1. Navigate to the project you want to configure for notifications.
1. Navigate to the [Integrations page](overview.md#accessing-integrations)
1. Click "Irker".
1. Select the "Active" checkbox.
1. Ensure that the **Active** toggle is enabled.
1. Enter the server host address where `irkerd` runs (defaults to `localhost`)
in the `Server host` field on the Web page
1. Enter the server port of `irkerd` (e.g. defaults to 6659) in the
......
......@@ -103,7 +103,7 @@ in a new slash command.
### Step 4. Copy the Mattermost token into the Mattermost slash command service
1. In GitLab, paste the Mattermost token you copied in the previous step and
check the **Active** checkbox.
ensure that the **Active** toggle is enabled.
![Mattermost copy token to GitLab](img/mattermost_gitlab_token.png)
......
......@@ -14,7 +14,7 @@ The Slack Notifications Service allows your GitLab project to send events (e.g.
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
1. Select the **Slack notifications** integration to configure it.
1. Check the **Active** checkbox to turn on the service.
1. Ensure that the **Active** toggle is enabled.
1. Check the checkboxes corresponding to the GitLab events you want to send to Slack as a notification.
1. For each event, optionally enter the Slack channel names where you want to send the event, separated by a comma. If left empty, the event will be sent to the default channel that you configured in the Slack Configuration step. **Note:** Usernames and private channels are not supported. To send direct messages, use the Member ID found under user's Slack profile.
1. Paste the **Webhook URL** that you copied from the Slack Configuration step.
......
......@@ -19,7 +19,7 @@ For GitLab.com, use the [Slack app](gitlab_slack_application.md) instead.
1. Enter a trigger term. We suggest you use the project name. Click **Add Slash Command Integration**.
1. Complete the rest of the fields in the Slack configuration page using information from the GitLab browser tab. In particular, the URL needs to be copied and pasted. Click **Save Integration** to complete the configuration in Slack.
1. While still on the Slack configuration page, copy the **token**. Go back to the GitLab browser tab and paste in the **token**.
1. Check the **Active** checkbox and click **Save changes** to complete the configuration in GitLab.
1. Ensure that the **Active** toggle is enabled and click **Save changes** to complete the configuration in GitLab.
![Slack setup instructions](img/slack_setup.png)
......
......@@ -17,7 +17,7 @@ When you have the **Webhook URL** for your Unify Circuit conversation webhook, y
1. Navigate to the [Integrations page](overview.md#accessing-integrations) in your project's settings, i.e. **Project > Settings > Integrations**.
1. Select the **Unify Circuit** integration to configure it.
1. Check the **Active** checkbox to turn on the service.
1. Ensure that the **Active** toggle is enabled.
1. Check the checkboxes corresponding to the GitLab events you want to receive in Unify Circuit.
1. Paste the **Webhook URL** that you copied from the Unify Circuit configuration step.
1. Configure the remaining options and click `Save changes`.
......
......@@ -489,7 +489,6 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc
end
def check_all_events
page.check('Active')
page.check('Push')
page.check('Issue')
page.check('Confidential issue')
......
......@@ -9,7 +9,7 @@ describe 'User activates issue tracker', :js do
let(:url) { 'http://tracker.example.com' }
def fill_short_form(disabled: false)
uncheck 'Active' if disabled
find('input[name="service[active]"] + button').click if disabled
fill_in 'service_project_url', with: url
fill_in 'service_issues_url', with: "#{url}/:id"
......
......@@ -10,7 +10,7 @@ describe 'User activates Jira', :js do
let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' }
def fill_form(disabled: false)
uncheck 'Active' if disabled
find('input[name="service[active]"] + button').click if disabled
fill_in 'service_url', with: url
fill_in 'service_username', with: 'username'
......@@ -53,7 +53,6 @@ describe 'User activates Jira', :js do
it 'shows errors when some required fields are not filled in' do
click_link('Jira')
check 'Active'
fill_in 'service_password', with: 'password'
click_button('Test settings and save changes')
......
......@@ -5,14 +5,13 @@ require 'spec_helper'
describe 'Set up Mattermost slash commands', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:service) { project.create_mattermost_slash_commands_service }
let(:mattermost_enabled) { true }
before do
stub_mattermost_setting(enabled: mattermost_enabled)
project.add_maintainer(user)
sign_in(user)
visit edit_project_service_path(project, service)
visit edit_project_service_path(project, :mattermost_slash_commands)
end
describe 'user visits the mattermost slash command config page' do
......@@ -30,6 +29,7 @@ describe 'Set up Mattermost slash commands', :js do
token = ('a'..'z').to_a.join
fill_in 'service_token', with: token
find('input[name="service[active]"] + button').click
click_on 'Save changes'
expect(current_path).to eq(project_settings_integrations_path(project))
......@@ -40,7 +40,6 @@ describe 'Set up Mattermost slash commands', :js do
token = ('a'..'z').to_a.join
fill_in 'service_token', with: token
check 'service_active'
click_on 'Save changes'
expect(current_path).to eq(project_settings_integrations_path(project))
......
......@@ -5,12 +5,11 @@ require 'spec_helper'
describe 'Slack slash commands' do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:service) { project.create_slack_slash_commands_service }
before do
project.add_maintainer(user)
sign_in(user)
visit edit_project_service_path(project, service)
visit edit_project_service_path(project, :slack_slash_commands)
end
it 'shows a token placeholder' do
......@@ -23,17 +22,17 @@ describe 'Slack slash commands' do
expect(page).to have_content('This service allows users to perform common')
end
it 'redirects to the integrations page after saving but not activating' do
it 'redirects to the integrations page after saving but not activating', :js do
fill_in 'service_token', with: 'token'
find('input[name="service[active]"] + button').click
click_on 'Save'
expect(current_path).to eq(project_settings_integrations_path(project))
expect(page).to have_content('Slack slash commands settings saved, but not activated.')
end
it 'redirects to the integrations page after activating' do
it 'redirects to the integrations page after activating', :js do
fill_in 'service_token', with: 'token'
check 'service_active'
click_on 'Save'
expect(current_path).to eq(project_settings_integrations_path(project))
......
......@@ -9,7 +9,7 @@ describe 'User activates issue tracker', :js do
let(:url) { 'http://tracker.example.com' }
def fill_form(disabled: false)
uncheck 'Active' if disabled
find('input[name="service[active]"] + button').click if disabled
fill_in 'service_project_url', with: url
fill_in 'service_issues_url', with: "#{url}/:id"
......
import { mount } from '@vue/test-utils';
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
import { GlToggle } from '@gitlab/ui';
const GL_TOGGLE_ACTIVE_CLASS = 'is-checked';
describe('ActiveToggle', () => {
let wrapper;
const defaultProps = {
initialActivated: true,
disabled: false,
};
const createComponent = props => {
wrapper = mount(ActiveToggle, {
propsData: Object.assign({}, defaultProps, props),
});
};
afterEach(() => {
if (wrapper) wrapper.destroy();
});
const findGlToggle = () => wrapper.find(GlToggle);
const findButtonInToggle = () => findGlToggle().find('button');
const findInputInToggle = () => findGlToggle().find('input');
describe('template', () => {
describe('initialActivated is false', () => {
it('renders GlToggle as inactive', () => {
createComponent({
initialActivated: false,
});
expect(findGlToggle().exists()).toBe(true);
expect(findButtonInToggle().classes()).not.toContain(GL_TOGGLE_ACTIVE_CLASS);
expect(findInputInToggle().attributes('value')).toBe('false');
});
});
describe('initialActivated is true', () => {
beforeEach(() => {
createComponent();
});
it('renders GlToggle as active', () => {
expect(findGlToggle().exists()).toBe(true);
expect(findButtonInToggle().classes()).toContain(GL_TOGGLE_ACTIVE_CLASS);
expect(findInputInToggle().attributes('value')).toBe('true');
});
describe('on toggle click', () => {
it('switches the form value', () => {
findButtonInToggle().trigger('click');
wrapper.vm.$nextTick(() => {
expect(findButtonInToggle().classes()).not.toContain(GL_TOGGLE_ACTIVE_CLASS);
expect(findInputInToggle().attributes('value')).toBe('false');
});
});
});
});
});
});
......@@ -23,9 +23,9 @@ describe('IntegrationSettingsForm', () => {
// Form Reference
expect(integrationSettingsForm.$form).toBeDefined();
expect(integrationSettingsForm.$form.prop('nodeName')).toEqual('FORM');
expect(integrationSettingsForm.formActive).toBeDefined();
// Form Child Elements
expect(integrationSettingsForm.$serviceToggle).toBeDefined();
expect(integrationSettingsForm.$submitBtn).toBeDefined();
expect(integrationSettingsForm.$submitBtnLoader).toBeDefined();
expect(integrationSettingsForm.$submitBtnLabel).toBeDefined();
......@@ -45,13 +45,15 @@ describe('IntegrationSettingsForm', () => {
});
it('should remove `novalidate` attribute to form when called with `true`', () => {
integrationSettingsForm.toggleServiceState(true);
integrationSettingsForm.formActive = true;
integrationSettingsForm.toggleServiceState();
expect(integrationSettingsForm.$form.attr('novalidate')).not.toBeDefined();
});
it('should set `novalidate` attribute to form when called with `false`', () => {
integrationSettingsForm.toggleServiceState(false);
integrationSettingsForm.formActive = false;
integrationSettingsForm.toggleServiceState();
expect(integrationSettingsForm.$form.attr('novalidate')).toBeDefined();
});
......@@ -66,8 +68,9 @@ describe('IntegrationSettingsForm', () => {
it('should set Save button label to "Test settings and save changes" when serviceActive & canTestService are `true`', () => {
integrationSettingsForm.canTestService = true;
integrationSettingsForm.formActive = true;
integrationSettingsForm.toggleSubmitBtnLabel(true);
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual(
'Test settings and save changes',
......@@ -76,18 +79,22 @@ describe('IntegrationSettingsForm', () => {
it('should set Save button label to "Save changes" when either serviceActive or canTestService (or both) is `false`', () => {
integrationSettingsForm.canTestService = false;
integrationSettingsForm.formActive = false;
integrationSettingsForm.toggleSubmitBtnLabel(false);
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
integrationSettingsForm.toggleSubmitBtnLabel(true);
integrationSettingsForm.formActive = true;
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
integrationSettingsForm.canTestService = true;
integrationSettingsForm.formActive = false;
integrationSettingsForm.toggleSubmitBtnLabel(false);
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
});
......
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