From bbb24da922f7e501571b5f356fd68257e75e4d40 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 12 Apr 2018 15:47:40 +0000 Subject: [PATCH] Resolve "Clean up old project permissions frontend code" --- .../javascripts/pages/projects/edit/index.js | 4 +- .../javascripts/pages/projects/new/index.js | 4 +- .../pages/projects/shared/project_new.js | 152 ------------------ .../projects/shared/save_project_loader.js | 12 ++ app/assets/javascripts/visibility_select.js | 21 --- app/helpers/projects_helper.rb | 66 -------- .../projects/_visibility_select.html.haml | 9 -- spec/helpers/projects_helper_spec.rb | 68 -------- spec/javascripts/visibility_select_spec.js | 98 ----------- 9 files changed, 16 insertions(+), 418 deletions(-) delete mode 100644 app/assets/javascripts/pages/projects/shared/project_new.js create mode 100644 app/assets/javascripts/pages/projects/shared/save_project_loader.js delete mode 100644 app/assets/javascripts/visibility_select.js delete mode 100644 app/views/projects/_visibility_select.html.haml delete mode 100644 spec/javascripts/visibility_select_spec.js diff --git a/app/assets/javascripts/pages/projects/edit/index.js b/app/assets/javascripts/pages/projects/edit/index.js index be37df36be8..628913483c6 100644 --- a/app/assets/javascripts/pages/projects/edit/index.js +++ b/app/assets/javascripts/pages/projects/edit/index.js @@ -1,12 +1,12 @@ import initSettingsPanels from '~/settings_panels'; import setupProjectEdit from '~/project_edit'; import initConfirmDangerModal from '~/confirm_danger_modal'; -import ProjectNew from '../shared/project_new'; +import initProjectLoadingSpinner from '../shared/save_project_loader'; import projectAvatar from '../shared/project_avatar'; import initProjectPermissionsSettings from '../shared/permissions'; document.addEventListener('DOMContentLoaded', () => { - new ProjectNew(); // eslint-disable-line no-new + initProjectLoadingSpinner(); setupProjectEdit(); // Initialize expandable settings panels initSettingsPanels(); diff --git a/app/assets/javascripts/pages/projects/new/index.js b/app/assets/javascripts/pages/projects/new/index.js index ea6fd961393..7db644e2477 100644 --- a/app/assets/javascripts/pages/projects/new/index.js +++ b/app/assets/javascripts/pages/projects/new/index.js @@ -1,9 +1,9 @@ -import ProjectNew from '../shared/project_new'; +import initProjectLoadingSpinner from '../shared/save_project_loader'; import initProjectVisibilitySelector from '../../../project_visibility'; import initProjectNew from '../../../projects/project_new'; document.addEventListener('DOMContentLoaded', () => { - new ProjectNew(); // eslint-disable-line no-new + initProjectLoadingSpinner(); initProjectVisibilitySelector(); initProjectNew.bindEvents(); }); diff --git a/app/assets/javascripts/pages/projects/shared/project_new.js b/app/assets/javascripts/pages/projects/shared/project_new.js deleted file mode 100644 index 56d5574aa2f..00000000000 --- a/app/assets/javascripts/pages/projects/shared/project_new.js +++ /dev/null @@ -1,152 +0,0 @@ -/* eslint-disable func-names, no-var, no-underscore-dangle, prefer-template, prefer-arrow-callback*/ - -import $ from 'jquery'; -import VisibilitySelect from '../../../visibility_select'; - -function highlightChanges($elm) { - $elm.addClass('highlight-changes'); - setTimeout(() => $elm.removeClass('highlight-changes'), 10); -} - -export default class ProjectNew { - constructor() { - this.toggleSettings = this.toggleSettings.bind(this); - this.$selects = $('.features select'); - this.$repoSelects = this.$selects.filter('.js-repo-select'); - this.$projectSelects = this.$selects.not('.js-repo-select'); - - $('.project-edit-container').on('ajax:before', () => { - $('.project-edit-container').hide(); - return $('.save-project-loader').show(); - }); - - this.initVisibilitySelect(); - - this.toggleSettings(); - this.toggleSettingsOnclick(); - this.toggleRepoVisibility(); - } - - initVisibilitySelect() { - const visibilityContainer = document.querySelector('.js-visibility-select'); - if (!visibilityContainer) return; - const visibilitySelect = new VisibilitySelect(visibilityContainer); - visibilitySelect.init(); - - const $visibilitySelect = $(visibilityContainer).find('select'); - let projectVisibility = $visibilitySelect.val(); - const PROJECT_VISIBILITY_PRIVATE = '0'; - - $visibilitySelect.on('change', () => { - const newProjectVisibility = $visibilitySelect.val(); - - if (projectVisibility !== newProjectVisibility) { - this.$projectSelects.each((idx, select) => { - const $select = $(select); - const $options = $select.find('option'); - const values = $.map($options, e => e.value); - - // if switched to "private", limit visibility options - if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) { - if ($select.val() !== values[0] && $select.val() !== values[1]) { - $select.val(values[1]).trigger('change'); - highlightChanges($select); - } - $options.slice(2).disable(); - } - - // if switched from "private", increase visibility for non-disabled options - if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) { - $options.enable(); - if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) { - $select.val(values[values.length - 1]).trigger('change'); - highlightChanges($select); - } - } - }); - - projectVisibility = newProjectVisibility; - } - }); - } - - toggleSettings() { - this.$selects.each(function () { - var $select = $(this); - var className = $select.data('field') - .replace(/_/g, '-') - .replace('access-level', 'feature'); - ProjectNew._showOrHide($select, '.' + className); - }); - } - - toggleSettingsOnclick() { - this.$selects.on('change', this.toggleSettings); - } - - static _showOrHide(checkElement, container) { - const $container = $(container); - - if ($(checkElement).val() !== '0') { - return $container.show(); - } - return $container.hide(); - } - - toggleRepoVisibility() { - var $repoAccessLevel = $('.js-repo-access-level select'); - var $lfsEnabledOption = $('.js-lfs-enabled select'); - var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; - var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); - var prevSelectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") - .nextAll() - .hide(); - - $repoAccessLevel - .off('change') - .on('change', function () { - var selectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.each(function () { - var $this = $(this); - var repoSelectVal = parseInt($this.val(), 10); - - $this.find('option').enable(); - - if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) { - $this.val(selectedVal).trigger('change'); - highlightChanges($this); - } - - $this.find("option[value='" + selectedVal + "']").nextAll().disable(); - }); - - if (selectedVal) { - this.$repoSelects.removeClass('disabled'); - - if ($lfsEnabledOption.length) { - $lfsEnabledOption.removeClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = ''; - } - } else { - this.$repoSelects.addClass('disabled'); - - if ($lfsEnabledOption.length) { - $lfsEnabledOption.val('false').addClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = 'none'; - containerRegistryCheckbox.checked = false; - } - } - - prevSelectedVal = selectedVal; - }.bind(this)); - } -} diff --git a/app/assets/javascripts/pages/projects/shared/save_project_loader.js b/app/assets/javascripts/pages/projects/shared/save_project_loader.js new file mode 100644 index 00000000000..aa3589ac88d --- /dev/null +++ b/app/assets/javascripts/pages/projects/shared/save_project_loader.js @@ -0,0 +1,12 @@ +import $ from 'jquery'; + +export default function initProjectLoadingSpinner() { + const $formContainer = $('.project-edit-container'); + const $loadingSpinner = $('.save-project-loader'); + + // show loading spinner when saving + $formContainer.on('ajax:before', () => { + $formContainer.hide(); + $loadingSpinner.show(); + }); +} diff --git a/app/assets/javascripts/visibility_select.js b/app/assets/javascripts/visibility_select.js deleted file mode 100644 index 0c928d0d5f6..00000000000 --- a/app/assets/javascripts/visibility_select.js +++ /dev/null @@ -1,21 +0,0 @@ -export default class VisibilitySelect { - constructor(container) { - if (!container) throw new Error('VisibilitySelect requires a container element as argument 1'); - this.container = container; - this.helpBlock = this.container.querySelector('.help-block'); - this.select = this.container.querySelector('select'); - } - - init() { - if (this.select) { - this.updateHelpText(); - this.select.addEventListener('change', this.updateHelpText.bind(this)); - } else { - this.helpBlock.textContent = this.container.querySelector('.js-locked').dataset.helpBlock; - } - } - - updateHelpText() { - this.helpBlock.textContent = this.select.querySelector('option:checked').dataset.description; - } -} diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 15f48e43a28..a64b2acdd77 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -157,40 +157,6 @@ module ProjectsHelper current_user&.recent_push(@project) end - def project_feature_access_select(field) - # Don't show option "everyone with access" if project is private - options = project_feature_options - - level = @project.project_feature.public_send(field) # rubocop:disable GitlabSecurity/PublicSend - - if @project.private? - disabled_option = ProjectFeature::ENABLED - highest_available_option = ProjectFeature::PRIVATE if level == disabled_option - end - - options = options_for_select( - options.invert, - selected: highest_available_option || level, - disabled: disabled_option - ) - - content_tag :div, class: "select-wrapper" do - concat( - content_tag( - :select, - options, - name: "project[project_feature_attributes][#{field}]", - id: "project_project_feature_attributes_#{field}", - class: "pull-right form-control select-control #{repo_children_classes(field)} ", - data: { field: field } - ) - ) - concat( - icon('chevron-down') - ) - end.html_safe - end - def link_to_autodeploy_doc link_to _('About auto deploy'), help_page_path('ci/autodeploy/index'), target: '_blank' end @@ -274,16 +240,6 @@ module ProjectsHelper private - def repo_children_classes(field) - needs_repo_check = [:merge_requests_access_level, :builds_access_level] - return unless needs_repo_check.include?(field) - - classes = "project-repo-select js-repo-select" - classes << " disabled" unless @project.feature_available?(:repository, current_user) - - classes - end - def get_project_nav_tabs(project, current_user) nav_tabs = [:home] @@ -447,14 +403,6 @@ module ProjectsHelper filtered_message.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]") end - def project_feature_options - { - ProjectFeature::DISABLED => s_('ProjectFeature|Disabled'), - ProjectFeature::PRIVATE => s_('ProjectFeature|Only team members'), - ProjectFeature::ENABLED => s_('ProjectFeature|Everyone with access') - } - end - def project_child_container_class(view_path) view_path == "projects/issues/issues" ? "prepend-top-default" : "project-show-#{view_path}" end @@ -463,20 +411,6 @@ module ProjectsHelper IssuesFinder.new(current_user, project_id: project.id).execute end - def visibility_select_options(project, selected_level) - level_options = Gitlab::VisibilityLevel.values.each_with_object([]) do |level, level_options| - next if restricted_levels.include?(level) - - level_options << [ - visibility_level_label(level), - { data: { description: visibility_level_description(level, project) } }, - level - ] - end - - options_for_select(level_options, selected_level) - end - def restricted_levels return [] if current_user.admin? diff --git a/app/views/projects/_visibility_select.html.haml b/app/views/projects/_visibility_select.html.haml deleted file mode 100644 index 4026b9e3c46..00000000000 --- a/app/views/projects/_visibility_select.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -- if can_change_visibility_level?(@project, current_user) - .select-wrapper - = form.select(model_method, visibility_select_options(@project, selected_level), {}, class: 'form-control visibility-select select-control') - = icon('chevron-down') -- else - .info.js-locked{ data: { help_block: visibility_level_description(@project.visibility_level, @project) } } - = visibility_level_icon(@project.visibility_level) - %strong - = visibility_level_label(@project.visibility_level) diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index ce96e90e2d7..46c55da24f8 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -322,74 +322,6 @@ describe ProjectsHelper do end end - describe "#project_feature_access_select" do - let(:project) { create(:project, :public) } - let(:user) { create(:user) } - - context "when project is internal or public" do - it "shows all options" do - helper.instance_variable_set(:@project, project) - result = helper.project_feature_access_select(:issues_access_level) - expect(result).to include("Disabled") - expect(result).to include("Only team members") - expect(result).to include("Everyone with access") - end - end - - context "when project is private" do - before do - project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - end - - it "shows only allowed options" do - helper.instance_variable_set(:@project, project) - result = helper.project_feature_access_select(:issues_access_level) - expect(result).to include("Disabled") - expect(result).to include("Only team members") - expect(result).to have_selector('option[disabled]', text: "Everyone with access") - end - end - - context "when project moves from public to private" do - before do - project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - end - - it "shows the highest allowed level selected" do - helper.instance_variable_set(:@project, project) - result = helper.project_feature_access_select(:issues_access_level) - - expect(result).to include("Disabled") - expect(result).to include("Only team members") - expect(result).to have_selector('option[disabled]', text: "Everyone with access") - expect(result).to have_selector('option[selected]', text: "Only team members") - end - end - end - - describe "#visibility_select_options" do - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } - - before do - allow(helper).to receive(:current_user).and_return(user) - - stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) - end - - it "does not include the Public restricted level" do - expect(helper.send(:visibility_select_options, project, Gitlab::VisibilityLevel::PRIVATE)).not_to include('Public') - end - - it "includes the Internal level" do - expect(helper.send(:visibility_select_options, project, Gitlab::VisibilityLevel::PRIVATE)).to include('Internal') - end - - it "includes the Private level" do - expect(helper.send(:visibility_select_options, project, Gitlab::VisibilityLevel::PRIVATE)).to include('Private') - end - end - describe '#get_project_nav_tabs' do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/javascripts/visibility_select_spec.js b/spec/javascripts/visibility_select_spec.js deleted file mode 100644 index 82714cb69bd..00000000000 --- a/spec/javascripts/visibility_select_spec.js +++ /dev/null @@ -1,98 +0,0 @@ -import VisibilitySelect from '~/visibility_select'; - -(() => { - describe('VisibilitySelect', function () { - const lockedElement = document.createElement('div'); - lockedElement.dataset.helpBlock = 'lockedHelpBlock'; - - const checkedElement = document.createElement('div'); - checkedElement.dataset.description = 'checkedDescription'; - - const mockElements = { - container: document.createElement('div'), - select: document.createElement('div'), - '.help-block': document.createElement('div'), - '.js-locked': lockedElement, - 'option:checked': checkedElement, - }; - - beforeEach(function () { - spyOn(Element.prototype, 'querySelector').and.callFake(selector => mockElements[selector]); - }); - - describe('constructor', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - }); - - it('sets the container member', function () { - expect(this.visibilitySelect.container).toEqual(mockElements.container); - }); - - it('queries and sets the helpBlock member', function () { - expect(Element.prototype.querySelector).toHaveBeenCalledWith('.help-block'); - expect(this.visibilitySelect.helpBlock).toEqual(mockElements['.help-block']); - }); - - it('queries and sets the select member', function () { - expect(Element.prototype.querySelector).toHaveBeenCalledWith('select'); - expect(this.visibilitySelect.select).toEqual(mockElements.select); - }); - - describe('if there is no container element provided', function () { - it('throws an error', function () { - expect(() => new VisibilitySelect()).toThrowError('VisibilitySelect requires a container element as argument 1'); - }); - }); - }); - - describe('init', function () { - describe('if there is a select', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - }); - - it('calls updateHelpText', function () { - spyOn(VisibilitySelect.prototype, 'updateHelpText'); - this.visibilitySelect.init(); - expect(this.visibilitySelect.updateHelpText).toHaveBeenCalled(); - }); - - it('adds a change event listener', function () { - spyOn(this.visibilitySelect.select, 'addEventListener'); - this.visibilitySelect.init(); - expect(this.visibilitySelect.select.addEventListener.calls.argsFor(0)).toContain('change'); - }); - }); - - describe('if there is no select', function () { - beforeEach(function () { - mockElements.select = undefined; - this.visibilitySelect = new VisibilitySelect(mockElements.container); - this.visibilitySelect.init(); - }); - - it('updates the helpBlock text to the locked `data-help-block` messaged', function () { - expect(this.visibilitySelect.helpBlock.textContent) - .toEqual(lockedElement.dataset.helpBlock); - }); - - afterEach(function () { - mockElements.select = document.createElement('div'); - }); - }); - }); - - describe('updateHelpText', function () { - beforeEach(function () { - this.visibilitySelect = new VisibilitySelect(mockElements.container); - this.visibilitySelect.init(); - }); - - it('updates the helpBlock text to the selected options `data-description`', function () { - expect(this.visibilitySelect.helpBlock.textContent) - .toEqual(checkedElement.dataset.description); - }); - }); - }); -})();