diff --git a/VERSION b/VERSION index ada2e4fce..ec6d649be 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.17.10 +1.18.1 diff --git a/app/assets/javascripts/repositories/index.js b/app/assets/javascripts/repositories/index.js index 638d8cff5..144b11cfe 100644 --- a/app/assets/javascripts/repositories/index.js +++ b/app/assets/javascripts/repositories/index.js @@ -108,18 +108,18 @@ var permissionCBs = form.find("input[name='write_permissions[]']"); var permissionChanges = form.find("input[name='permission_changes']"); var submitBtn = form.find('input[type="submit"]'); - var selectAllCheckbox = form.find('.all-teams .simple-checkbox'); + var selectAllCheckbox = form.find('.all-teams .sci-checkbox'); - form.find('.teams-list').find('input.simple-checkbox, .permission-selector') + form.find('.teams-list').find('input.sci-checkbox, .permission-selector') .toggleClass('hidden', selectAllCheckbox.is(':checked')); - form.find('.all-teams .trigger-checkbox') + form.find('.all-teams .sci-toggle-checkbox') .toggleClass('hidden', !selectAllCheckbox.is(':checked')) .attr('disabled', !selectAllCheckbox.is(':checked')); selectAllCheckbox.change(function() { - form.find('.teams-list').find('input.simple-checkbox, .permission-selector') + form.find('.teams-list').find('input.sci-checkbox, .permission-selector') .toggleClass('hidden', this.checked); - form.find('.all-teams .trigger-checkbox').toggleClass('hidden', !this.checked) + form.find('.all-teams .sci-toggle-checkbox').toggleClass('hidden', !this.checked) .attr('disabled', !this.checked); }); diff --git a/app/assets/javascripts/repositories/repository_datatable.js b/app/assets/javascripts/repositories/repository_datatable.js index 10be0e2bd..1c758c3b2 100644 --- a/app/assets/javascripts/repositories/repository_datatable.js +++ b/app/assets/javascripts/repositories/repository_datatable.js @@ -17,6 +17,7 @@ var RepositoryDatatable = (function(global) { var SELECT_ALL_SELECTOR = "#checkbox > input[name=select_all]" var rowsSelected = []; + var rowsLocked = []; // Tells whether we're currently viewing or editing table var currentMode = 'viewMode'; @@ -76,6 +77,11 @@ var RepositoryDatatable = (function(global) { $('#copyRepositoryRecords').prop('disabled', false); $('#assignRepositoryRecords').prop('disabled', false); $('#unassignRepositoryRecords').prop('disabled', false); + + if (rowsSelected.some(r=> rowsLocked.indexOf(r) >= 0)) { // Some selected rows is rowsLocked + $('#editRepositoryRecord').prop('disabled', true); + $('#deleteRepositoryRecordsButton').prop('disabled', true); + } $('#editDeleteCopy').show(); } } else if (currentMode === 'editMode') { @@ -422,8 +428,9 @@ var RepositoryDatatable = (function(global) { orderable: false, className: 'dt-body-center', sWidth: '1%', - render: function() { - return ""; + render: function(data, type, row) { + return ` + `; } }, { // Assigned column is not searchable @@ -433,11 +440,13 @@ var RepositoryDatatable = (function(global) { orderable: true, className: 'assigned-column', sWidth: '1%', - render: function(data) { + render: function(data, type, row) { let content = data; - if (EDITABLE) { - content = '' + content; + let icon = ''; + if (!row.recordEditable) { + icon = ``; } + content = icon + content; return content; } }, { @@ -461,6 +470,7 @@ var RepositoryDatatable = (function(global) { sSearch: I18n.t('general.filter_dots') }, rowCallback: function(row, data) { + $(row).attr('data-editable', data.recordEditable); // Get row ID let rowId = data.DT_RowId; // If row ID is in the list of selected row IDs @@ -576,6 +586,10 @@ var RepositoryDatatable = (function(global) { $('.dataTables_filter').find('label').remove(); $('.main-actions, .pagination-row').removeClass('hidden'); + + $(TABLE_ID).find('tr[data-editable=false]').each(function(_, e) { + rowsLocked.push(parseInt($(e).attr('id'), 10)); + }); } }); diff --git a/app/assets/javascripts/repository_columns/columns_initializers/status_column_type.js b/app/assets/javascripts/repository_columns/columns_initializers/status_column_type.js index 45e71d66d..a26eecaa6 100644 --- a/app/assets/javascripts/repository_columns/columns_initializers/status_column_type.js +++ b/app/assets/javascripts/repository_columns/columns_initializers/status_column_type.js @@ -24,12 +24,12 @@ var RepositoryStatusColumnType = (function() { $.each($statusRows, (index, statusRow) => { var $row = $(statusRow); var $statusField = $row.find('.status-item-field'); - var iconPlaceholder = $row.find(iconId).attr('emoji'); + var icon = $row.find(iconId).attr('emoji'); var stringLength = $statusField.val().length; if (stringLength < GLOBAL_CONSTANTS.NAME_MIN_LENGTH || stringLength > GLOBAL_CONSTANTS.NAME_MAX_LENGTH - || !iconPlaceholder) { + || !icon) { $row.addClass('error').attr('data-error-text', I18n.t('libraries.manange_modal_column.status_type.errors.icon_and_name_error')); } else { $row.removeClass('error'); @@ -55,6 +55,7 @@ var RepositoryStatusColumnType = (function() { var iconElement = this; picker.on('emoji', emoji => { $(iconElement).attr('emoji', emoji).html(twemoji.parse(emoji)); + validateForm(); }); if (picker.pickerVisible) { diff --git a/app/assets/stylesheets/my_modules/repositories.scss b/app/assets/stylesheets/my_modules/repositories.scss index a2c0bd294..34443255a 100644 --- a/app/assets/stylesheets/my_modules/repositories.scss +++ b/app/assets/stylesheets/my_modules/repositories.scss @@ -21,8 +21,15 @@ } tbody { - tr:hover { + tr { + .assigned-column { + .repository-row-lock-icon { + display: none !important; + } + } + } + tr:hover { .assigned-column { .repository-row-edit-icon { display: none !important; diff --git a/app/assets/stylesheets/repositories.scss b/app/assets/stylesheets/repositories.scss index 946c89f8f..2dc7907e4 100644 --- a/app/assets/stylesheets/repositories.scss +++ b/app/assets/stylesheets/repositories.scss @@ -116,6 +116,7 @@ padding-top: 123px; .dataTables_scrollHead { + position: -webkit-sticky !important; position: sticky !important; top: 194px; z-index: 90; @@ -418,13 +419,8 @@ display: flex; padding: 5px 0; - .simple-checkbox.hidden { + .sci-checkbox.hidden { display: inline-block !important; - - + .checkbox-label { - display: inline-block; - opacity: 0; - } } } } @@ -441,7 +437,7 @@ display: flex; flex-grow: 1; - .checkbox-label { + .sci-checkbox-container { margin-right: 5px; } } @@ -470,4 +466,3 @@ color: $color-silver-chalice; } } - diff --git a/app/assets/stylesheets/repository/repository_table.scss b/app/assets/stylesheets/repository/repository_table.scss index 2853b0d4f..75999a961 100644 --- a/app/assets/stylesheets/repository/repository_table.scss +++ b/app/assets/stylesheets/repository/repository_table.scss @@ -33,6 +33,10 @@ width: 30px; } + .repository-row-lock-icon { + width: 30px; + } + .assign-counter-container { border-radius: $border-radius-tag; cursor: pointer; @@ -198,6 +202,12 @@ .editing { border: 1px solid; } + + tr[data-editable=false] { + .assign-counter-container { + margin-left: 0; + } + } } &.editing { diff --git a/app/assets/stylesheets/shared/checkbox.scss b/app/assets/stylesheets/shared/checkbox.scss deleted file mode 100644 index f62fe718f..000000000 --- a/app/assets/stylesheets/shared/checkbox.scss +++ /dev/null @@ -1,108 +0,0 @@ -// scss-lint:disable SelectorDepth SelectorFormat QualifyingElement -// scss-lint:disable NestingDepth ImportantRule - -@import "constants"; -@import "mixins"; - -:root { - --checkbox-size: 16px; -} - -input[type="checkbox"].simple-checkbox { - cursor: pointer; - flex-shrink: 0; - height: var(--checkbox-size); - margin: 0; - opacity: 0; - position: relative; - width: var(--checkbox-size); - z-index: 2; - - + .checkbox-label { - display: inline-block; - flex-shrink: 0; - height: var(--checkbox-size); - margin-left: calc((var(--checkbox-size) * -1) - 1px); - position: relative; - width: var(--checkbox-size); - - &::before { - content: "\f0c8"; - font-family: "Font Awesome 5 Free"; - font-size: var(--checkbox-size); - font-weight: 400; - left: 0; - line-height: var(--checkbox-size); - position: absolute; - text-align: center; - top: 1px; - width: var(--checkbox-size); - } - } - - &.disabled { - pointer-events: none; - - + .checkbox-label { - color: $color-silver-chalice; - cursor: not-allowed; - } - } - - &.hidden + .checkbox-label { - display: none; - } - - &:checked + .checkbox-label { - &::before { - content: "\f14a"; - } - } -} - -input[type="checkbox"].trigger-checkbox { - cursor: pointer; - flex-shrink: 0; - height: 16px; - margin: 0; - opacity: 0; - position: relative; - width: 24px; - z-index: 2; - - + .checkbox-label { - background: $color-silver-chalice; - border-radius: 8px; - display: inline-block; - flex-shrink: 0; - height: 16px; - margin-left: -24px; - position: relative; - transition: .2s; - width: 24px; - - &::before { - background: $color-white; - border-radius: 7px; - content: ""; - height: 12px; - left: 0; - margin: 2px; - position: absolute; - transition: .2s; - width: 12px; - } - } - - &.hidden + .checkbox-label { - display: none; - } - - &:checked + .checkbox-label { - background: $brand-success; - - &::before { - left: 8px; - } - } -} diff --git a/app/assets/stylesheets/shared_styles/elements/checkboxes.scss b/app/assets/stylesheets/shared_styles/elements/checkboxes.scss index 66dbe2cd5..d19779aa2 100644 --- a/app/assets/stylesheets/shared_styles/elements/checkboxes.scss +++ b/app/assets/stylesheets/shared_styles/elements/checkboxes.scss @@ -4,6 +4,13 @@ --sci-checkbox-size: 16px; } +.sci-checkbox-container { + display: inline-block; + height: var(--sci-checkbox-size); + position: relative; + width: var(--sci-checkbox-size); +} + input[type="checkbox"].sci-checkbox { cursor: pointer; flex-shrink: 0; @@ -36,7 +43,6 @@ input[type="checkbox"].sci-checkbox { line-height: calc(var(--sci-checkbox-size) - 2px); position: absolute; text-align: center; - top: 1px; transition: .2s; width: var(--sci-checkbox-size); } diff --git a/app/assets/stylesheets/shared_styles/elements/toggles.scss b/app/assets/stylesheets/shared_styles/elements/toggles.scss index e95ae09c6..b5937e8db 100644 --- a/app/assets/stylesheets/shared_styles/elements/toggles.scss +++ b/app/assets/stylesheets/shared_styles/elements/toggles.scss @@ -1,5 +1,12 @@ // scss-lint:disable SelectorDepth QualifyingElement NestingDepth +.sci-toggle-checkbox-container { + display: inline-block; + height: 16px; + position: relative; + width: 24px; +} + input[type="checkbox"].sci-toggle-checkbox { cursor: pointer; flex-shrink: 0; @@ -17,8 +24,9 @@ input[type="checkbox"].sci-toggle-checkbox { display: inline-block; flex-shrink: 0; height: 16px; - margin-left: -27px; - position: relative; + left: 0; + position: absolute; + top: 0; transition: .2s; width: 24px; diff --git a/app/controllers/repository_columns/checklist_columns_controller.rb b/app/controllers/repository_columns/checklist_columns_controller.rb index c3adf3cd6..0d9af4e56 100644 --- a/app/controllers/repository_columns/checklist_columns_controller.rb +++ b/app/controllers/repository_columns/checklist_columns_controller.rb @@ -4,7 +4,7 @@ module RepositoryColumns class ChecklistColumnsController < BaseColumnsController before_action :load_column, only: %i(update destroy items) before_action :check_create_permissions, only: :create - before_action :check_manage_permissions, only: %i(update destroy items) + before_action :check_manage_permissions, only: %i(update destroy) helper_method :delimiters def create diff --git a/app/controllers/repository_columns/list_columns_controller.rb b/app/controllers/repository_columns/list_columns_controller.rb index 88be0397e..63649506d 100644 --- a/app/controllers/repository_columns/list_columns_controller.rb +++ b/app/controllers/repository_columns/list_columns_controller.rb @@ -4,7 +4,7 @@ module RepositoryColumns class ListColumnsController < BaseColumnsController before_action :load_column, only: %i(update destroy items) before_action :check_create_permissions, only: :create - before_action :check_manage_permissions, only: %i(update destroy items) + before_action :check_manage_permissions, only: %i(update destroy) helper_method :delimiters def create diff --git a/app/controllers/repository_columns/status_columns_controller.rb b/app/controllers/repository_columns/status_columns_controller.rb index 30b515531..9142b0fc3 100644 --- a/app/controllers/repository_columns/status_columns_controller.rb +++ b/app/controllers/repository_columns/status_columns_controller.rb @@ -5,7 +5,7 @@ module RepositoryColumns include InputSanitizeHelper before_action :load_column, only: %i(update destroy items) before_action :check_create_permissions, only: :create - before_action :check_manage_permissions, only: %i(update destroy items) + before_action :check_manage_permissions, only: %i(update destroy) def create service = RepositoryColumns::CreateColumnService diff --git a/app/helpers/repository_datatable_helper.rb b/app/helpers/repository_datatable_helper.rb index 86b6537bf..a54b1cec2 100644 --- a/app/helpers/repository_datatable_helper.rb +++ b/app/helpers/repository_datatable_helper.rb @@ -28,7 +28,8 @@ module RepositoryDatatableHelper record.id ), 'recordInfoUrl': Rails.application.routes.url_helpers - .repository_row_path(record.id) + .repository_row_path(record.id), + 'recordEditable': record.editable? } # Add custom columns diff --git a/app/models/repository_checklist_item.rb b/app/models/repository_checklist_item.rb index 7bf66000c..f25165bfd 100644 --- a/app/models/repository_checklist_item.rb +++ b/app/models/repository_checklist_item.rb @@ -11,5 +11,5 @@ class RepositoryChecklistItem < ApplicationRecord belongs_to :last_modified_by, foreign_key: 'last_modified_by_id', class_name: 'User', inverse_of: :modified_repository_checklist_types has_many :repository_checklist_items_values, dependent: :destroy - has_many :repository_checklist_values, through: :repository_checklist_items_values + has_many :repository_checklist_values, through: :repository_checklist_items_values, dependent: :destroy end diff --git a/app/models/repository_row.rb b/app/models/repository_row.rb index 6fb472b51..eb87cbf7b 100644 --- a/app/models/repository_row.rb +++ b/app/models/repository_row.rb @@ -37,4 +37,8 @@ class RepositoryRow < ApplicationRecord .where('repositories.team_id = ? and repository_rows.created_by_id = ?', team, user) .update_all(created_by_id: new_owner.id) end + + def editable? + true + end end diff --git a/app/serializers/repository_datatable/repository_list_value_serializer.rb b/app/serializers/repository_datatable/repository_list_value_serializer.rb index d47deb4d3..2631870e8 100644 --- a/app/serializers/repository_datatable/repository_list_value_serializer.rb +++ b/app/serializers/repository_datatable/repository_list_value_serializer.rb @@ -4,8 +4,8 @@ module RepositoryDatatable class RepositoryListValueSerializer < RepositoryBaseValueSerializer def value { - id: object.repository_list_item.id, - text: object.data + id: (object.repository_list_item&.id || ''), + text: (object.data || '') } end end diff --git a/app/services/repository_datatable_service.rb b/app/services/repository_datatable_service.rb index 6692a4d29..415f6ecf6 100644 --- a/app/services/repository_datatable_service.rb +++ b/app/services/repository_datatable_service.rb @@ -52,6 +52,7 @@ class RepositoryDatatableService .select('COUNT(DISTINCT my_modules.experiment_id) AS "assigned_experiments_count"') .select('COUNT(DISTINCT experiments.project_id) AS "assigned_projects_count"') end + repository_rows = repository_rows.preload(Extends::REPOSITORY_ROWS_PRELOAD_RELATIONS) @repository_rows = sort_rows(order_obj, repository_rows) end diff --git a/app/views/repositories/_share_repository_modal.html.erb b/app/views/repositories/_share_repository_modal.html.erb index 5f7d3141a..67e45bf49 100644 --- a/app/views/repositories/_share_repository_modal.html.erb +++ b/app/views/repositories/_share_repository_modal.html.erb @@ -17,29 +17,37 @@