Commit 37944794 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch...

Merge branch '12975-the-field-enter-new-password-in-service-templates-pages-should-show-asterisks-in-the-password' into 'master'

Clean up integration form titles and password fields

See merge request gitlab-org/gitlab!56309
parents 07480d53 9f60dcee
......@@ -3,7 +3,6 @@
import { GlFormGroup, GlFormCheckbox, GlFormInput, GlFormSelect, GlFormTextarea } from '@gitlab/ui';
import { capitalize, lowerCase, isEmpty } from 'lodash';
import { mapGetters } from 'vuex';
import { __, sprintf } from '~/locale';
import eventHub from '../event_hub';
export default {
......@@ -77,14 +76,6 @@ export default {
isNonEmptyPassword() {
return this.isPassword && !isEmpty(this.value);
},
label() {
if (this.isNonEmptyPassword) {
return sprintf(__('Enter new %{field_title}'), {
field_title: this.humanizedTitle,
});
}
return this.humanizedTitle;
},
humanizedTitle() {
return this.title || capitalize(lowerCase(this.name));
},
......@@ -136,7 +127,7 @@ export default {
<template>
<gl-form-group
:label="label"
:label="humanizedTitle"
:label-for="fieldId"
:invalid-feedback="__('This field is required.')"
:state="valid"
......
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import IntegrationForm from './components/integration_form.vue';
import { createStore } from './store';
......@@ -73,7 +74,7 @@ function parseDatasetToProps(data) {
},
learnMorePath,
triggerEvents: JSON.parse(triggerEvents),
fields: JSON.parse(fields),
fields: convertObjectPropsToCamelCase(JSON.parse(fields), { deep: true }),
inheritFromId: parseInt(inheritFromId, 10),
integrationLevel,
id: parseInt(id, 10),
......
......@@ -36,6 +36,7 @@ https://app.asana.com/0/developer-console'
{
type: 'text',
name: 'api_key',
title: _('API key'),
placeholder: s_('AsanaService|User Personal Access Token. User must have access to task, all comments will be attributed to this user.'),
required: true
},
......
......@@ -48,13 +48,30 @@ class BambooService < CiService
def fields
[
{ type: 'text', name: 'bamboo_url',
placeholder: s_('BambooService|Bamboo root URL like https://bamboo.example.com'), required: true },
{ type: 'text', name: 'build_key',
placeholder: s_('BambooService|Bamboo build plan key like KEY'), required: true },
{ type: 'text', name: 'username',
placeholder: s_('BambooService|A user with API access, if applicable') },
{ type: 'password', name: 'password' }
{
type: 'text',
name: 'bamboo_url',
title: s_('BambooService|Bamboo URL'),
placeholder: s_('BambooService|Bamboo root URL like https://bamboo.example.com'),
required: true
},
{
type: 'text',
name: 'build_key',
placeholder: s_('BambooService|Bamboo build plan key like KEY'),
required: true
},
{
type: 'text',
name: 'username',
placeholder: s_('BambooService|A user with API access, if applicable')
},
{
type: 'password',
name: 'password',
non_empty_password_title: s_('ProjectService|Enter new password'),
non_empty_password_help: s_('ProjectService|Leave blank to use your current password')
}
]
end
......
......@@ -17,9 +17,9 @@ class CustomIssueTrackerService < IssueTrackerService
def fields
[
{ type: 'text', name: 'project_url', placeholder: 'Project url', required: true },
{ type: 'text', name: 'issues_url', placeholder: 'Issue url', required: true },
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url', required: true }
{ type: 'text', name: 'project_url', title: _('Project URL'), required: true },
{ type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), required: true },
{ type: 'text', name: 'new_issue_url', title: s_('ProjectService|New issue URL'), required: true }
]
end
end
......@@ -78,7 +78,9 @@ class DatadogService < Service
{
type: 'password',
name: 'api_key',
title: 'API key',
title: _('API key'),
non_empty_password_title: s_('ProjectService|Enter new API key'),
non_empty_password_help: s_('ProjectService|Leave blank to use your current API key'),
help: "<a href=\"#{api_keys_url}\" target=\"_blank\">API key</a> used for authentication with Datadog",
required: true
},
......
......@@ -93,7 +93,7 @@ class DroneCiService < CiService
def fields
[
{ type: 'text', name: 'token', placeholder: 'Drone CI project specific token', required: true },
{ type: 'text', name: 'drone_url', placeholder: 'http://drone.example.com', required: true },
{ type: 'text', name: 'drone_url', title: s_('ProjectService|Drone URL'), placeholder: 'http://drone.example.com', required: true },
{ type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" }
]
end
......
......@@ -6,7 +6,7 @@ class ExternalWikiService < Service
validates :external_wiki_url, presence: true, public_url: true, if: :activated?
def title
s_('ExternalWikiService|External Wiki')
s_('ExternalWikiService|External wiki')
end
def description
......@@ -22,7 +22,8 @@ class ExternalWikiService < Service
{
type: 'text',
name: 'external_wiki_url',
placeholder: s_('ExternalWikiService|The URL of the external Wiki'),
title: s_('ExternalWikiService|External wiki URL'),
placeholder: s_('ExternalWikiService|The URL of the external wiki'),
required: true
}
]
......
......@@ -39,7 +39,7 @@ class HipchatService < Service
{ type: 'text', name: 'room', placeholder: 'Room name or ID' },
{ type: 'checkbox', name: 'notify' },
{ type: 'select', name: 'color', choices: %w(yellow red green purple gray random) },
{ type: 'text', name: 'api_version',
{ type: 'text', name: 'api_version', title: _('API version'),
placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' },
......
......@@ -73,9 +73,9 @@ class IssueTrackerService < Service
def fields
[
{ type: 'text', name: 'project_url', placeholder: 'Project url', required: true },
{ type: 'text', name: 'issues_url', placeholder: 'Issue url', required: true },
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url', required: true }
{ type: 'text', name: 'project_url', title: _('Project URL'), required: true },
{ type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), required: true },
{ type: 'text', name: 'new_issue_url', title: s_('ProjectService|New issue URL'), required: true }
]
end
......
......@@ -77,15 +77,30 @@ class JenkinsService < CiService
def fields
[
{
type: 'text', name: 'jenkins_url',
type: 'text',
name: 'jenkins_url',
title: s_('ProjectService|Jenkins URL'),
required: true,
placeholder: 'Jenkins URL like http://jenkins.example.com'
},
{
type: 'text', name: 'project_name', placeholder: 'Project Name',
type: 'text',
name: 'project_name',
required: true,
placeholder: 'Project Name',
help: 'The URL-friendly project name. Example: my_project_name'
},
{ type: 'text', name: 'username' },
{ type: 'password', name: 'password' }
{
type: 'text',
name: 'username',
required: true
},
{
type: 'password',
name: 'password',
non_empty_password_title: s_('ProjectService|Enter new password'),
non_empty_password_help: s_('ProjectService|Leave blank to use your current password')
}
]
end
end
......@@ -128,11 +128,42 @@ class JiraService < IssueTrackerService
transition_id_help_link_start = '<a href="%{transition_id_help_path}" target="_blank" rel="noopener noreferrer">'.html_safe % { transition_id_help_path: transition_id_help_path }
[
{ type: 'text', name: 'url', title: s_('JiraService|Web URL'), placeholder: 'https://jira.example.com', required: true },
{ type: 'text', name: 'api_url', title: s_('JiraService|Jira API URL'), placeholder: s_('JiraService|If different from Web URL') },
{ type: 'text', name: 'username', title: s_('JiraService|Username or Email'), placeholder: s_('JiraService|Use a username for server version and an email for cloud version'), required: true },
{ type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true },
{ type: 'text', name: 'jira_issue_transition_id', title: s_('JiraService|Jira workflow transition IDs'), placeholder: s_('JiraService|For example, 12, 24'), help: s_('JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}'.html_safe % { link_start: transition_id_help_link_start, link_end: '</a>'.html_safe }) }
{
type: 'text',
name: 'url',
title: s_('JiraService|Web URL'),
placeholder: 'https://jira.example.com',
required: true
},
{
type: 'text',
name: 'api_url',
title: s_('JiraService|Jira API URL'),
placeholder: s_('JiraService|If different from Web URL')
},
{
type: 'text',
name: 'username',
title: s_('JiraService|Username or Email'),
placeholder: s_('JiraService|Use a username for server version and an email for cloud version'),
required: true
},
{
type: 'password',
name: 'password',
title: s_('JiraService|Password or API token'),
non_empty_password_title: s_('JiraService|Enter new password or API token'),
non_empty_password_help: s_('JiraService|Leave blank to use your current password or API token'),
placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'),
required: true
},
{
type: 'text',
name: 'jira_issue_transition_id',
title: s_('JiraService|Jira workflow transition IDs'),
placeholder: s_('JiraService|For example, 12, 24'),
help: s_('JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}'.html_safe % { link_start: transition_id_help_link_start, link_end: '</a>'.html_safe })
}
]
end
......
......@@ -21,10 +21,13 @@ class MockCiService < CiService
def fields
[
{ type: 'text',
{
type: 'text',
name: 'mock_service_url',
title: s_('ProjectService|Mock service URL'),
placeholder: 'http://localhost:4004',
required: true }
required: true
}
]
end
......
......@@ -20,7 +20,7 @@ class PushoverService < Service
def fields
[
{ type: 'text', name: 'api_key', placeholder: s_('PushoverService|Your application key'), required: true },
{ type: 'text', name: 'api_key', title: _('API key'), placeholder: s_('PushoverService|Your application key'), required: true },
{ type: 'text', name: 'user_key', placeholder: s_('PushoverService|Your user key'), required: true },
{ type: 'text', name: 'device', placeholder: s_('PushoverService|Leave blank for all active devices') },
{ type: 'select', name: 'priority', required: true, choices:
......
......@@ -65,13 +65,30 @@ class TeamcityService < CiService
def fields
[
{ type: 'text', name: 'teamcity_url',
placeholder: 'TeamCity root URL like https://teamcity.example.com', required: true },
{ type: 'text', name: 'build_type',
placeholder: 'Build configuration ID', required: true },
{ type: 'text', name: 'username',
placeholder: 'A user with permissions to trigger a manual build' },
{ type: 'password', name: 'password' }
{
type: 'text',
name: 'teamcity_url',
title: s_('ProjectService|TeamCity URL'),
placeholder: 'TeamCity root URL like https://teamcity.example.com',
required: true
},
{
type: 'text',
name: 'build_type',
placeholder: 'Build configuration ID',
required: true
},
{
type: 'text',
name: 'username',
placeholder: 'A user with permissions to trigger a manual build'
},
{
type: 'password',
name: 'password',
non_empty_password_title: s_('ProjectService|Enter new password'),
non_empty_password_help: s_('ProjectService|Leave blank to use your current password')
}
]
end
......
......@@ -26,8 +26,8 @@ class YoutrackService < IssueTrackerService
def fields
[
{ type: 'text', name: 'project_url', title: 'Project URL', placeholder: 'Project URL', required: true },
{ type: 'text', name: 'issues_url', title: 'Issue URL', placeholder: 'Issue URL', required: true }
{ type: 'text', name: 'project_url', title: _('Project URL'), required: true },
{ type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), required: true }
]
end
end
......@@ -2,14 +2,22 @@
class ServiceFieldEntity < Grape::Entity
include RequestAwareEntity
include Gitlab::Utils::StrongMemoize
expose :type, :name, :title, :placeholder, :required, :choices, :help
expose :type, :name, :placeholder, :required, :choices
expose :title do |field|
non_empty_password?(field) ? field[:non_empty_password_title] : field[:title]
end
expose :help do |field|
non_empty_password?(field) ? field[:non_empty_password_help] : field[:help]
end
expose :value do |field|
# field[:name] is not user input and so can assume is safe
value = service.public_send(field[:name]) # rubocop:disable GitlabSecurity/PublicSend
value = value_for(field)
if field[:type] == 'password' && value.present?
if non_empty_password?(field)
'true'
elsif field[:type] == 'checkbox'
ActiveRecord::Type::Boolean.new.deserialize(value).to_s
......@@ -23,4 +31,17 @@ class ServiceFieldEntity < Grape::Entity
def service
request.service
end
def value_for(field)
strong_memoize(:value_for) do
# field[:name] is not user input and so can assume is safe
service.public_send(field[:name]) # rubocop:disable GitlabSecurity/PublicSend
end
end
def non_empty_password?(field)
strong_memoize(:non_empty_password) do
field[:type] == 'password' && value_for(field).present?
end
end
end
......@@ -346,12 +346,12 @@
.nav-icon-container
= sprite_icon('external-link')
%span.nav-item-name
= _('External Wiki')
= s_('ExternalWikiService|External wiki')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: "fly-out-top-item" } ) do
= link_to external_wiki_url do
%strong.fly-out-top-item-name
= _('External Wiki')
= s_('ExternalWikiService|External wiki')
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
......
---
title: Clean up integration form titles and password fields
merge_request: 56309
author:
type: changed
......@@ -536,13 +536,13 @@ Get Confluence service settings for a project.
GET /projects/:id/services/confluence
```
## External Wiki
## External wiki
Replaces the link to the internal wiki with a link to an external wiki.
### Create/Edit External Wiki service
### Create/Edit External wiki service
Set External Wiki service for a project.
Set External wiki service for a project.
```plaintext
PUT /projects/:id/services/external-wiki
......@@ -552,19 +552,19 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `external_wiki_url` | string | true | The URL of the external Wiki |
| `external_wiki_url` | string | true | The URL of the external wiki |
### Delete External Wiki service
### Delete External wiki service
Delete External Wiki service for a project.
Delete External wiki service for a project.
```plaintext
DELETE /projects/:id/services/external-wiki
```
### Get External Wiki service settings
### Get External wiki service settings
Get External Wiki service settings for a project.
Get External wiki service settings for a project.
```plaintext
GET /projects/:id/services/external-wiki
......
......@@ -37,7 +37,7 @@ Click on the service links to see further configuration instructions and details
| [Discord Notifications](discord_notifications.md) | Receive event notifications in Discord | No |
| Drone CI | Continuous Integration platform built on Docker, written in Go | Yes |
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients | No |
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki | No |
| External wiki | Replaces the link to the internal wiki with a link to an external wiki | No |
| Flowdock | Flowdock is a collaboration web app for technical teams | No |
| [Generic alerts](../../../operations/incident_management/integrations.md) **(ULTIMATE)** | Receive alerts on GitLab from any source | No |
| [GitHub](github.md) **(PREMIUM)** | Sends pipeline notifications to GitHub | No |
......
......@@ -394,7 +394,7 @@ module API
required: true,
name: :external_wiki_url,
type: String,
desc: 'The URL of the external Wiki'
desc: 'The URL of the external wiki'
}
],
'flowdock' => [
......
......@@ -1461,6 +1461,12 @@ msgstr ""
msgid "API Token"
msgstr ""
msgid "API key"
msgstr ""
msgid "API version"
msgstr ""
msgid "APIFuzzing|API Fuzzing Configuration"
msgstr ""
......@@ -4680,6 +4686,9 @@ msgstr ""
msgid "BambooService|Atlassian Bamboo CI"
msgstr ""
msgid "BambooService|Bamboo URL"
msgstr ""
msgid "BambooService|Bamboo build plan key like KEY"
msgstr ""
......@@ -11678,9 +11687,6 @@ msgstr ""
msgid "Enter merge request URLs"
msgstr ""
msgid "Enter new %{field_title}"
msgstr ""
msgid "Enter new AWS Secret Access Key"
msgstr ""
......@@ -12623,9 +12629,6 @@ msgstr ""
msgid "External URL"
msgstr ""
msgid "External Wiki"
msgstr ""
msgid "External authentication"
msgstr ""
......@@ -12647,13 +12650,16 @@ msgstr ""
msgid "ExternalAuthorizationService|When no classification label is set the default label `%{default_label}` will be used."
msgstr ""
msgid "ExternalWikiService|External Wiki"
msgid "ExternalWikiService|External wiki"
msgstr ""
msgid "ExternalWikiService|External wiki URL"
msgstr ""
msgid "ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki."
msgstr ""
msgid "ExternalWikiService|The URL of the external Wiki"
msgid "ExternalWikiService|The URL of the external wiki"
msgstr ""
msgid "Facebook"
......@@ -17359,6 +17365,9 @@ msgstr ""
msgid "JiraService|Enable Jira issues creation from vulnerabilities"
msgstr ""
msgid "JiraService|Enter new password or API token"
msgstr ""
msgid "JiraService|Events for %{noteable_model_name} are disabled."
msgstr ""
......@@ -17407,6 +17416,9 @@ msgstr ""
msgid "JiraService|Jira workflow transition IDs"
msgstr ""
msgid "JiraService|Leave blank to use your current password or API token"
msgstr ""
msgid "JiraService|Not all data may be displayed here. To view more details or make changes to this issue, go to %{linkStart}Jira%{linkEnd}."
msgstr ""
......@@ -23893,6 +23905,15 @@ msgstr ""
msgid "ProjectService|%{service_title}: status on"
msgstr ""
msgid "ProjectService|Drone URL"
msgstr ""
msgid "ProjectService|Enter new API key"
msgstr ""
msgid "ProjectService|Enter new password"
msgstr ""
msgid "ProjectService|Event will be triggered by a push to the repository"
msgstr ""
......@@ -23929,9 +23950,30 @@ msgstr ""
msgid "ProjectService|Event will be triggered when someone adds a comment on a confidential issue"
msgstr ""
msgid "ProjectService|Issue URL"
msgstr ""
msgid "ProjectService|Jenkins URL"
msgstr ""
msgid "ProjectService|Leave blank to use your current API key"
msgstr ""
msgid "ProjectService|Leave blank to use your current password"
msgstr ""
msgid "ProjectService|Mock service URL"
msgstr ""
msgid "ProjectService|New issue URL"
msgstr ""
msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
msgstr ""
msgid "ProjectService|TeamCity URL"
msgstr ""
msgid "ProjectService|To set up this service:"
msgstr ""
......
......@@ -7,7 +7,7 @@ RSpec.describe 'User activates Asana' do
it 'activates service', :js do
visit_project_integration('Asana')
fill_in('Api key', with: 'verySecret')
fill_in('API key', with: 'verySecret')
fill_in('Restrict to branch', with: 'verySecret')
click_test_then_save_integration
......
......@@ -11,7 +11,7 @@ RSpec.describe 'User activates Atlassian Bamboo CI' do
it 'activates service', :js do
visit_project_integration('Atlassian Bamboo CI')
fill_in('Bamboo url', with: 'http://bamboo.example.com')
fill_in('Bamboo URL', with: 'http://bamboo.example.com')
fill_in('Build key', with: 'KEY')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
......@@ -23,6 +23,7 @@ RSpec.describe 'User activates Atlassian Bamboo CI' do
# Password field should not be filled in.
click_link('Atlassian Bamboo CI')
expect(find_field('Enter new Password').value).to be_blank
expect(find_field('Enter new password').value).to be_blank
expect(page).to have_content('Leave blank to use your current password')
end
end
......@@ -13,7 +13,7 @@ RSpec.describe 'User activates JetBrains TeamCity CI' do
visit_project_integration('JetBrains TeamCity CI')
check('Push')
check('Merge Request')
fill_in('Teamcity url', with: 'http://teamcity.example.com')
fill_in('TeamCity URL', with: 'http://teamcity.example.com')
fill_in('Build type', with: 'GitlabTest_Build')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
......
......@@ -11,7 +11,7 @@ RSpec.describe 'User activates Pushover' do
it 'activates service', :js do
visit_project_integration('Pushover')
fill_in('Api key', with: 'verySecret')
fill_in('API key', with: 'verySecret')
fill_in('User key', with: 'verySecret')
fill_in('Device', with: 'myDevice')
select('High Priority', from: 'Priority')
......
......@@ -192,17 +192,6 @@ describe('DynamicField', () => {
expect(findGlFormGroup().find('label').text()).toBe(defaultProps.title);
});
describe('for password field with some value (hidden by backend)', () => {
it('renders label with new password title', () => {
createComponent({
type: 'password',
value: 'true',
});
expect(findGlFormGroup().find('label').text()).toBe(`Enter new ${defaultProps.title}`);
});
});
});
describe('validations', () => {
......
......@@ -41,11 +41,11 @@ RSpec.describe ServiceFieldEntity do
expected_hash = {
type: 'password',
name: 'password',
title: 'Password or API token',
title: 'Enter new password or API token',
placeholder: 'Use a password for server version and an API token for cloud version',
required: true,
choices: nil,
help: nil,
help: 'Leave blank to use your current password or API token',
value: 'true'
}
......
......@@ -146,7 +146,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'shows the external wiki tab with the external wiki service link' do
render
expect(rendered).to have_link('External Wiki', href: properties['external_wiki_url'])
expect(rendered).to have_link('External wiki', href: properties['external_wiki_url'])
end
end
......@@ -156,7 +156,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
it 'does not show the external wiki tab' do
render
expect(rendered).not_to have_link('External Wiki')
expect(rendered).not_to have_link('External wiki')
end
end
end
......
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