Commit 898c5da4 authored by Bob Van Landuyt's avatar Bob Van Landuyt

Merge branch '13904-tab-width-option' into 'master'

Add tab width option to user preferences

See merge request gitlab-org/gitlab!22063
parents aa9e23e7 eba0b5c9
...@@ -28,6 +28,13 @@ ...@@ -28,6 +28,13 @@
} }
} }
@for $i from 1 through 12 {
#{'.tab-width-#{$i}'} {
-moz-tab-size: $i;
tab-size: $i;
}
}
.border-width-1px { border-width: 1px; } .border-width-1px { border-width: 1px; }
.border-bottom-width-1px { border-bottom-width: 1px; } .border-bottom-width-1px { border-bottom-width: 1px; }
.border-style-dashed { border-style: dashed; } .border-style-dashed { border-style: dashed; }
......
...@@ -48,6 +48,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController ...@@ -48,6 +48,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:time_display_relative, :time_display_relative,
:time_format_in_24h, :time_format_in_24h,
:show_whitespace_in_diffs, :show_whitespace_in_diffs,
:tab_width,
:sourcegraph_enabled, :sourcegraph_enabled,
:render_whitespace_in_code :render_whitespace_in_code
] ]
......
...@@ -63,6 +63,10 @@ module PreferencesHelper ...@@ -63,6 +63,10 @@ module PreferencesHelper
Gitlab::ColorSchemes.for_user(current_user).css_class Gitlab::ColorSchemes.for_user(current_user).css_class
end end
def user_tab_width
Gitlab::TabWidth.css_class_for_user(current_user)
end
def language_choices def language_choices
Gitlab::I18n::AVAILABLE_LANGUAGES.map { |value, label| [label, value] } Gitlab::I18n::AVAILABLE_LANGUAGES.map { |value, label| [label, value] }
end end
......
...@@ -248,6 +248,7 @@ class User < ApplicationRecord ...@@ -248,6 +248,7 @@ class User < ApplicationRecord
delegate :time_display_relative, :time_display_relative=, to: :user_preference delegate :time_display_relative, :time_display_relative=, to: :user_preference
delegate :time_format_in_24h, :time_format_in_24h=, to: :user_preference delegate :time_format_in_24h, :time_format_in_24h=, to: :user_preference
delegate :show_whitespace_in_diffs, :show_whitespace_in_diffs=, to: :user_preference delegate :show_whitespace_in_diffs, :show_whitespace_in_diffs=, to: :user_preference
delegate :tab_width, :tab_width=, to: :user_preference
delegate :sourcegraph_enabled, :sourcegraph_enabled=, to: :user_preference delegate :sourcegraph_enabled, :sourcegraph_enabled=, to: :user_preference
delegate :setup_for_company, :setup_for_company=, to: :user_preference delegate :setup_for_company, :setup_for_company=, to: :user_preference
delegate :render_whitespace_in_code, :render_whitespace_in_code=, to: :user_preference delegate :render_whitespace_in_code, :render_whitespace_in_code=, to: :user_preference
......
...@@ -9,7 +9,13 @@ class UserPreference < ApplicationRecord ...@@ -9,7 +9,13 @@ class UserPreference < ApplicationRecord
belongs_to :user belongs_to :user
validates :issue_notes_filter, :merge_request_notes_filter, inclusion: { in: NOTES_FILTERS.values }, presence: true validates :issue_notes_filter, :merge_request_notes_filter, inclusion: { in: NOTES_FILTERS.values }, presence: true
validates :tab_width, numericality: {
only_integer: true,
greater_than_or_equal_to: Gitlab::TabWidth::MIN,
less_than_or_equal_to: Gitlab::TabWidth::MAX
}
default_value_for :tab_width, value: Gitlab::TabWidth::DEFAULT, allows_nil: false
default_value_for :timezone, value: Time.zone.tzinfo.name, allows_nil: false default_value_for :timezone, value: Time.zone.tzinfo.name, allows_nil: false
default_value_for :time_display_relative, value: true, allows_nil: false default_value_for :time_display_relative, value: true, allows_nil: false
default_value_for :time_format_in_24h, value: false, allows_nil: false default_value_for :time_format_in_24h, value: false, allows_nil: false
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
!!! 5 !!! 5
%html{ lang: I18n.locale, class: page_classes } %html{ lang: I18n.locale, class: page_classes }
= render "layouts/head" = render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class} #{client_class_list}", data: body_data } %body{ class: "#{user_application_theme} #{user_tab_width} #{@body_class} #{client_class_list}", data: body_data }
= render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_auto_complete" if @gfm_form
= render "layouts/init_client_detection_flags" = render "layouts/init_client_detection_flags"
= render 'peek/bar' = render 'peek/bar'
......
!!! 5 !!! 5
%html{ lang: I18n.locale, class: page_class } %html{ lang: I18n.locale, class: page_class }
= render "layouts/head" = render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class} fullscreen-layout", data: { page: body_data_page } } %body{ class: "#{user_application_theme} #{user_tab_width} #{@body_class} fullscreen-layout", data: { page: body_data_page } }
= render 'peek/bar' = render 'peek/bar'
= header_message = header_message
= render partial: "layouts/header/default", locals: { project: @project, group: @group } = render partial: "layouts/header/default", locals: { project: @project, group: @group }
......
...@@ -69,6 +69,15 @@ ...@@ -69,6 +69,15 @@
= f.check_box :show_whitespace_in_diffs, class: 'form-check-input' = f.check_box :show_whitespace_in_diffs, class: 'form-check-input'
= f.label :show_whitespace_in_diffs, class: 'form-check-label' do = f.label :show_whitespace_in_diffs, class: 'form-check-label' do
= s_('Preferences|Show whitespace changes in diffs') = s_('Preferences|Show whitespace changes in diffs')
.form-group
= f.label :tab_width, s_('Preferences|Tab width'), class: 'label-bold'
= f.number_field :tab_width,
class: 'form-control',
min: Gitlab::TabWidth::MIN,
max: Gitlab::TabWidth::MAX,
required: true
.form-text.text-muted
= s_('Preferences|Must be a number between %{min} and %{max}') % { min: Gitlab::TabWidth::MIN, max: Gitlab::TabWidth::MAX }
.col-sm-12 .col-sm-12
%hr %hr
......
...@@ -12,5 +12,9 @@ if ('<%= current_user.layout %>' === 'fluid') { ...@@ -12,5 +12,9 @@ if ('<%= current_user.layout %>' === 'fluid') {
// Re-enable the "Save" button // Re-enable the "Save" button
$('input[type=submit]').enable() $('input[type=submit]').enable()
// Show the notice flash message // Show flash messages
new Flash('<%= flash.discard(:notice) %>', 'notice') <% if flash.notice %>
new Flash('<%= flash.discard(:notice) %>', 'notice')
<% elsif flash.alert %>
new Flash('<%= flash.discard(:alert) %>', 'alert')
<% end %>
---
title: Add tab width option to user preferences
merge_request: 22063
author: Alexander Oleynikov
type: added
# frozen_string_literal: true
class AddTabWidthToUserPreferences < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_column(:user_preferences, :tab_width, :integer, limit: 2)
end
end
...@@ -4142,6 +4142,7 @@ ActiveRecord::Schema.define(version: 2020_02_04_131054) do ...@@ -4142,6 +4142,7 @@ ActiveRecord::Schema.define(version: 2020_02_04_131054) do
t.boolean "sourcegraph_enabled" t.boolean "sourcegraph_enabled"
t.boolean "setup_for_company" t.boolean "setup_for_company"
t.boolean "render_whitespace_in_code" t.boolean "render_whitespace_in_code"
t.integer "tab_width", limit: 2
t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true t.index ["user_id"], name: "index_user_preferences_on_user_id", unique: true
end end
......
...@@ -108,6 +108,15 @@ You can choose between 3 options: ...@@ -108,6 +108,15 @@ You can choose between 3 options:
- Readme - Readme
- Activity - Activity
### Tab width
You can set the displayed width of tab characters across various parts of
GitLab, for example, blobs, diffs, and snippets.
NOTE: **Note:**
Some parts of GitLab do not respect this setting, including the WebIDE, file
editor and Markdown editor.
## Localization ## Localization
### Language ### Language
......
# frozen_string_literal: true
module Gitlab
module TabWidth
extend self
MIN = 1
MAX = 12
DEFAULT = 8
def css_class_for_user(user)
return css_class_for_value(DEFAULT) unless user
css_class_for_value(user.tab_width)
end
private
def css_class_for_value(value)
raise ArgumentError unless in_range?(value)
"tab-width-#{value}"
end
def in_range?(value)
(MIN..MAX).cover?(value)
end
end
end
...@@ -13963,6 +13963,9 @@ msgstr "" ...@@ -13963,6 +13963,9 @@ msgstr ""
msgid "Preferences|Layout width" msgid "Preferences|Layout width"
msgstr "" msgstr ""
msgid "Preferences|Must be a number between %{min} and %{max}"
msgstr ""
msgid "Preferences|Navigation theme" msgid "Preferences|Navigation theme"
msgstr "" msgstr ""
...@@ -13981,6 +13984,9 @@ msgstr "" ...@@ -13981,6 +13984,9 @@ msgstr ""
msgid "Preferences|Syntax highlighting theme" msgid "Preferences|Syntax highlighting theme"
msgstr "" msgstr ""
msgid "Preferences|Tab width"
msgstr ""
msgid "Preferences|These settings will update how dates and times are displayed for you." msgid "Preferences|These settings will update how dates and times are displayed for you."
msgstr "" msgstr ""
......
...@@ -47,6 +47,7 @@ describe Profiles::PreferencesController do ...@@ -47,6 +47,7 @@ describe Profiles::PreferencesController do
theme_id: '2', theme_id: '2',
first_day_of_week: '1', first_day_of_week: '1',
preferred_language: 'jp', preferred_language: 'jp',
tab_width: '5',
render_whitespace_in_code: 'true' render_whitespace_in_code: 'true'
}.with_indifferent_access }.with_indifferent_access
......
...@@ -29,4 +29,31 @@ describe 'User edit preferences profile' do ...@@ -29,4 +29,31 @@ describe 'User edit preferences profile' do
expect(field).not_to be_checked expect(field).not_to be_checked
end end
describe 'User changes tab width to acceptable value' do
it 'shows success message' do
fill_in 'Tab width', with: 9
click_button 'Save changes'
expect(page).to have_content('Preferences saved.')
end
it 'saves the value' do
tab_width_field = page.find_field('Tab width')
expect do
tab_width_field.fill_in with: 6
click_button 'Save changes'
end.to change { tab_width_field.value }
end
end
describe 'User changes tab width to unacceptable value' do
it 'shows error message' do
fill_in 'Tab width', with: -1
click_button 'Save changes'
expect(page).to have_content('Failed to save preferences')
end
end
end end
# frozen_string_literal: true
require 'fast_spec_helper'
describe Gitlab::TabWidth, lib: true do
describe '.css_class_for_user' do
it 'returns default CSS class when user is nil' do
css_class = described_class.css_class_for_user(nil)
expect(css_class).to eq('tab-width-8')
end
it "returns CSS class for user's tab width", :aggregate_failures do
[1, 6, 12].each do |i|
user = double('user', tab_width: i)
css_class = described_class.css_class_for_user(user)
expect(css_class).to eq("tab-width-#{i}")
end
end
it 'raises if tab width is out of valid range', :aggregate_failures do
[0, 13, 'foo', nil].each do |i|
expect do
user = double('user', tab_width: i)
described_class.css_class_for_user(user)
end.to raise_error(ArgumentError)
end
end
end
end
...@@ -85,4 +85,19 @@ describe UserPreference do ...@@ -85,4 +85,19 @@ describe UserPreference do
expect(user_preference.timezone).to eq(Time.zone.tzinfo.name) expect(user_preference.timezone).to eq(Time.zone.tzinfo.name)
end end
end end
describe '#tab_width' do
it 'is set to 8 by default' do
# Intentionally not using factory here to test the constructor.
pref = UserPreference.new
expect(pref.tab_width).to eq(8)
end
it do
is_expected.to validate_numericality_of(:tab_width)
.only_integer
.is_greater_than_or_equal_to(1)
.is_less_than_or_equal_to(12)
end
end
end end
...@@ -20,6 +20,9 @@ describe User, :do_not_mock_admin_mode do ...@@ -20,6 +20,9 @@ describe User, :do_not_mock_admin_mode do
describe 'delegations' do describe 'delegations' do
it { is_expected.to delegate_method(:path).to(:namespace).with_prefix } it { is_expected.to delegate_method(:path).to(:namespace).with_prefix }
it { is_expected.to delegate_method(:tab_width).to(:user_preference) }
it { is_expected.to delegate_method(:tab_width=).to(:user_preference).with_arguments(5) }
end end
describe 'associations' do describe 'associations' 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