diff options
Diffstat (limited to 'app')
31 files changed, 532 insertions, 204 deletions
diff --git a/app/assets/stylesheets/framework/blank.scss b/app/assets/stylesheets/framework/blank.scss index a2fa2e7769b..c0224d3bfa9 100644 --- a/app/assets/stylesheets/framework/blank.scss +++ b/app/assets/stylesheets/framework/blank.scss @@ -1,6 +1,29 @@ +.blank-state-parent-container { + display: flex; + + .section-container { + display: flex; + flex: 1; + padding: 10px; + } + + .section-body { + width: 100%; + height: 100%; + padding-bottom: 25px; + border: 1px solid $border-color; + border-radius: $border-radius-default; + + &.section-ee-trial { + display: flex; + align-items: center; + justify-content: center; + } + } +} + .blank-state-welcome { text-align: center; - border-bottom: 1px solid $border-color; .blank-state-text { margin-bottom: 0; @@ -10,6 +33,10 @@ .blank-state { padding-top: 20px; padding-bottom: 20px; +} + +.blank-state.ee-trial { + padding: 20px; text-align: center; } @@ -20,20 +47,24 @@ .blank-state-icon { padding-bottom: 20px; - color: $gray-darkest; font-size: 56px; - path, - polygon { - fill: currentColor; + svg { + display: block; + margin: auto; + } +} + +@media (min-width: $screen-sm-max) { + .section-welcome .blank-state-icon svg { + width: 130%; } } .blank-state-title { margin-top: 0; - margin-bottom: 5px; + margin-bottom: 10px; font-size: 18px; - font-weight: normal; } .blank-state-text { @@ -49,3 +80,24 @@ .blank-state-welcome-title { font-size: 24px; } + +@media (max-width: $screen-md-min) { + .blank-state-parent-container { + &, + .section-container { + display: block; + } + } + + .blank-state { + text-align: center; + } + + .blank-state-icon { + padding-bottom: 0; + } + + .blank-state-body { + margin-top: 15px; + } +} diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 38727e15c6f..e59cd0eea82 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -343,6 +343,12 @@ ul.indent-list { .group-row { padding: 0; border: none; + + &:last-of-type { + .group-row-contents:not(:hover) { + border-bottom: 1px solid transparent; + } + } } .group-row-contents { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 23555e8e3e6..3f032776d82 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -74,11 +74,17 @@ $red-700: #a62d19; $red-800: #8b2615; $red-900: #711e11; -$purple-600: #6e49cb; -$purple-650: #5c35ae; -$purple-700: #4a2192; -$purple-800: #2c0a5c; -$purple-900: #380d75; +$indigo-50: #f7f7ff; +$indigo-100: #ebebfa; +$indigo-200: #d1d1f0; +$indigo-300: #a6a6de; +$indigo-400: #7c7ccc; +$indigo-500: #6666c4; +$indigo-600: #5b5bbd; +$indigo-700: #4b4ba3; +$indigo-800: #393982; +$indigo-900: #292961; +$indigo-950: #1a1a40; $black: #000; $black-transparent: rgba(0, 0, 0, 0.3); diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss index bfb7a0c7e25..73cb3a7cf4c 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/new_nav.scss @@ -4,7 +4,7 @@ header.navbar-gitlab-new { color: $white-light; - background-color: $purple-900; + background: linear-gradient(to right, $indigo-900, $indigo-800); border-bottom: 0; .header-content { @@ -24,11 +24,9 @@ header.navbar-gitlab-new { > a { display: flex; align-items: center; - padding-top: 3px; padding-right: $gl-padding; padding-left: $gl-padding; margin-left: -$gl-padding; - border-bottom: 3px solid transparent; @media (min-width: $screen-sm-min) { padding-right: $gl-padding; @@ -45,9 +43,8 @@ header.navbar-gitlab-new { &:hover, &:focus { - color: currentColor; + color: $tanuki-yellow; text-decoration: none; - border-bottom-color: $white-light; } } } @@ -71,7 +68,7 @@ header.navbar-gitlab-new { .navbar-collapse { padding-left: 0; - color: $white-light; + color: $indigo-200; box-shadow: 0; @media (max-width: $screen-xs-max) { @@ -101,7 +98,7 @@ header.navbar-gitlab-new { font-size: 14px; text-align: center; color: currentColor; - border-left: 1px solid lighten($purple-700, 10%); + border-left: 1px solid lighten($indigo-700, 10%); &:hover, &:focus, @@ -120,6 +117,7 @@ header.navbar-gitlab-new { li { .badge { box-shadow: none; + font-weight: 600; } } } @@ -133,12 +131,11 @@ header.navbar-gitlab-new { > a { background: none; - opacity: .9; - will-change: opacity; + will-change: color; &.header-user-dropdown-toggle { .header-user-avatar { - border-color: $white-light; + border-color: $indigo-200; } } @@ -165,29 +162,34 @@ header.navbar-gitlab-new { .navbar-sub-nav { display: flex; margin-bottom: 0; - color: $white-light; + color: $indigo-200; > li { - &.active > a, - a:hover, - a:focus { - border-bottom-color: $white-light; + > a:hover, + > a:focus { + box-shadow: inset 0 -3px 0 rgba($indigo-200, .4); text-decoration: none; outline: 0; - opacity: 1; + color: $white-light; + } + + &.active > a { + box-shadow: inset 0 -3px 0 $indigo-500; + color: $white-light; + font-weight: 700; } > a { display: block; - padding: 16px 10px 13px; + padding: 16px 10px; font-size: 13px; color: currentColor; - border-bottom: 3px solid transparent; - opacity: .9; - will-change: opacity; + box-shadow: inset 0 0 0 transparent; + will-change: box-shadow; + transition: box-shadow 0.15s; @media (min-width: $screen-sm-min) { - padding: 15px $gl-padding 12px; + padding: 15px $gl-padding; font-size: 14px; } } @@ -207,55 +209,60 @@ header.navbar-gitlab-new { .search { form { - border-color: $purple-800; + border: 0; + background-color: rgba($indigo-200, .2); + transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s, background-color ease-in-out 0.15s; &:hover { - border-color: rgba($white-light, .6); + background-color: rgba($indigo-200, .3); box-shadow: none; } } &.search-active form { - border-color: $white-light; - } - - form, - .search-input { - background-color: $purple-700; + background-color: rgba($indigo-200, .3); + box-shadow: none; } .search-input { color: $white-light; + background: none; } .search-input::placeholder { - color: rgba($white-light, .6); + color: rgba($indigo-200, .8); } .location-badge { font-size: 12px; - color: rgba($white-light, .6); - background-color: $purple-800; + color: $indigo-100; + background-color: rgba($indigo-200, .1); transition: color 0.15s; will-change: color; + margin: -4px 4px -4px -4px; + line-height: 25px; + padding: 4px 8px; + border-radius: 2px 0 0 2px; + border-right: 1px solid $indigo-800; + height: 34px; } .search-input-wrap { .search-icon, .clear-icon { - color: rgba($white-light, .6); + color: rgba($indigo-200, .8); } } &.search-active { .location-badge { color: $white-light; - background-color: $purple-800; + background-color: rgba($indigo-200, .2); } .search-input-wrap { .search-icon { - color: rgba($white-light, .6); + color: rgba($indigo-200, .8); } .clear-icon { diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss index f9ceaec9418..96459fe31cc 100644 --- a/app/assets/stylesheets/new_sidebar.scss +++ b/app/assets/stylesheets/new_sidebar.scss @@ -2,6 +2,15 @@ @import 'framework/tw_bootstrap_variables'; @import "bootstrap/variables"; +$active-background: rgba(0,0,0,.04); +$active-border: $indigo-500; +$active-color: $indigo-700; +$active-hover-background: $active-background; +$active-hover-color: $gl-text-color; +$inactive-badge-background: rgba(0,0,0,.08); +$hover-background: $indigo-700; +$hover-color: $white-light; +$inactive-color: $gl-text-color-secondary; $new-sidebar-width: 220px; .page-with-new-sidebar { @@ -17,19 +26,33 @@ $new-sidebar-width: 220px; } .context-header { - background-color: $gray-normal; border-bottom: 1px solid $border-color; font-weight: 600; display: flex; align-items: center; - padding: 10px 14px; + padding: 10px 16px 10px 10px; + color: $gl-text-color; .avatar-container { flex: 0 0 40px; } &:hover { - background-color: $border-color; + background-color: $hover-background; + color: $hover-color; + border-color: $hover-background; + + .avatar-container { + border-color: transparent; + } + + .settings-avatar { + background-color: $indigo-500; + + i { + color: $hover-color; + } + } } .project-title, @@ -41,6 +64,7 @@ $new-sidebar-width: 220px; .settings-avatar { background-color: $white-light; + transition: background-color 100ms linear; i { font-size: 20px; @@ -48,6 +72,7 @@ $new-sidebar-width: 220px; color: $gl-text-color-secondary; text-align: center; align-self: center; + transition: color 100ms linear; } } @@ -60,11 +85,15 @@ $new-sidebar-width: 220px; bottom: 0; left: 0; overflow: auto; - background-color: $gray-light; - border-right: 1px solid $border-color; + background-color: $gray-normal; + box-shadow: inset -2px 0 0 $border-color; + + a { + text-decoration: none; + } ul { - padding: 0; + padding-left: 0; list-style: none; } @@ -73,13 +102,18 @@ $new-sidebar-width: 220px; a { display: block; - padding: 12px 14px; + padding: 12px 16px; + color: $inactive-color; } } - a { - color: $gl-text-color; - text-decoration: none; + li.active { + box-shadow: inset 4px 0 0 $active-border; + + > a { + color: $active-color; + font-weight: 700; + } } @media (max-width: $screen-xs-max) { @@ -89,22 +123,28 @@ $new-sidebar-width: 220px; .sidebar-sub-level-items { display: none; + padding-bottom: 8px; > li { a { - padding: 12px 24px; - color: $gl-text-color-light; + font-size: 12px; + padding: 8px 16px 8px 24px; - &:hover { - color: $gl-text-color; - background-color: $border-color; + &:hover, + &:focus { + background: $active-hover-background; + color: $active-hover-color; } } &.active { - > a { - color: $purple-650; - font-weight: 600; + a { + &, + &:hover, + &:focus { + background: $active-background; + color: $active-color; + } } } } @@ -114,35 +154,31 @@ $new-sidebar-width: 220px; > li { .badge { float: right; - background-color: $border-color; - color: $gl-text-color; + background-color: $inactive-badge-background; + color: $inactive-color; } &.active { - > a { - background-color: $purple-600; - color: $white-light; - font-weight: 600; - } + background: $active-background; .badge { - background-color: $purple-700; - color: $white-light; + color: $active-color; + font-weight: 600; } .sidebar-sub-level-items { - background-color: $gray-normal; - border-left: 6px solid $purple-600; display: block; } } - &:not(.active) > a:hover { - background-color: $border-color; + > a:hover { + background-color: $hover-background; + color: $hover-color; .badge { - transition: background-color 100ms linear; - background-color: $gray-normal; + transition: background-color 100ms linear, color 100ms linear; + background-color: $indigo-500; + color: $hover-color; } } } @@ -161,3 +197,13 @@ $new-sidebar-width: 220px; // scss-lint:enable DuplicateProperty } } + + +// Change color of all horizontal tabs to match the new indigo color +.nav-links li.active a { + border-bottom-color: $active-border; + + .badge { + font-weight: 600; + } +} diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index f21005895e4..e7c07ef67f0 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -54,8 +54,6 @@ @media (min-width: $screen-sm-min) { display: -webkit-flex; display: flex; - width: 400px; - max-width: 50%; } } @@ -65,7 +63,6 @@ @media (min-width: $screen-sm-min) { display: -webkit-flex; display: flex; - width: 100%; margin-top: 3px; } } @@ -81,18 +78,10 @@ .member-form-control { @media (max-width: $screen-xs-max) { - padding: 5px 0; + padding-bottom: 5px; margin-left: 0; margin-right: 0; } - - @media (min-width: $screen-sm-min) { - width: 50%; - } - - .dropdown-menu-toggle { - width: 100%; - } } .member-access-text { @@ -216,3 +205,102 @@ } } } + +.content-list.members-list li { + display: flex; + justify-content: space-between; + + .list-item-name { + float: none; + display: flex; + flex: 1; + } + + .user-info { + padding-right: 10px; + } + + .member { + font-weight: bold; + overflow-wrap: break-word; + word-break: break-all; + } + + .member-group-link { + display: inline-block; + } + + .form-control { + width: inherit; + } + + .btn { + align-self: flex-start; + } + + .form-horizontal ~ .btn { + margin-right: 0; + } + + @media (max-width: $screen-xs-max) { + display: block; + + .controls > .btn { + margin-left: 0; + margin-right: 0; + display: block; + } + + .form-control { + width: 100%; + } + + .member-access-text { + line-height: 0; + margin-left: 50px; + } + + .member-controls { + margin-top: 5px; + } + + .form-horizontal { + margin-top: 10px; + } + } +} + +.panel-mobile { + .content-list.members-list li { + display: block; + + .member-controls { + float: none; + display: block; + } + + .dropdown-menu-toggle, + .dropdown-menu, + .form-control, + .list-item-name { + width: 100%; + } + + .dropdown-menu { + margin-top: 0; + } + + .form-horizontal { + display: block; + } + + .member-form-control { + margin: 5px 0; + } + + .btn { + width: 100%; + margin-left: 0; + } + } +} diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index c207159f606..235c475ff26 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -286,8 +286,7 @@ table.u2f-registrations { } .user-callout { - margin: 0 auto; - max-width: $screen-lg-min; + margin: 20px -5px 0; .bordered-box { border: 1px solid $blue-300; diff --git a/app/finders/concerns/created_at_filter.rb b/app/finders/concerns/created_at_filter.rb new file mode 100644 index 00000000000..ac9ac77732c --- /dev/null +++ b/app/finders/concerns/created_at_filter.rb @@ -0,0 +1,8 @@ +module CreatedAtFilter + def by_created_at(items) + items = items.created_before(params[:created_before]) if params[:created_before].present? + items = items.created_after(params[:created_after]) if params[:created_after].present? + + items + end +end diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index d81e9ed17d4..2e5a6493134 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -19,6 +19,8 @@ # iids: integer[] # class IssuableFinder + include CreatedAtFilter + NONE = '0'.freeze IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page].freeze @@ -32,6 +34,7 @@ class IssuableFinder def execute items = init_collection items = by_scope(items) + items = by_created_at(items) items = by_state(items) items = by_group(items) items = by_search(items) @@ -42,7 +45,6 @@ class IssuableFinder items = by_iids(items) items = by_milestone(items) items = by_label(items) - items = by_created_at(items) # Filtering by project HAS TO be the last because we use the project IDs yielded by the issuable query thus far items = by_project(items) @@ -411,18 +413,6 @@ class IssuableFinder params[:non_archived].present? ? items.non_archived : items end - def by_created_at(items) - if params[:created_after].present? - items = items.where(items.klass.arel_table[:created_at].gteq(params[:created_after])) - end - - if params[:created_before].present? - items = items.where(items.klass.arel_table[:created_at].lteq(params[:created_before])) - end - - items - end - def current_user_related? params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me' end diff --git a/app/finders/milestones_finder.rb b/app/finders/milestones_finder.rb index 23c42a5f662..0a5a0ea2f35 100644 --- a/app/finders/milestones_finder.rb +++ b/app/finders/milestones_finder.rb @@ -49,7 +49,8 @@ class MilestonesFinder if params.has_key?(:order) items.reorder(params[:order]) else - items.reorder('due_date ASC') + order_statement = Gitlab::Database.nulls_last_order('due_date', 'ASC') + items.reorder(order_statement) end end end diff --git a/app/finders/users_finder.rb b/app/finders/users_finder.rb index 07deceb827b..33f7ae90598 100644 --- a/app/finders/users_finder.rb +++ b/app/finders/users_finder.rb @@ -14,6 +14,8 @@ # external: boolean # class UsersFinder + include CreatedAtFilter + attr_accessor :current_user, :params def initialize(current_user, params = {}) @@ -29,6 +31,7 @@ class UsersFinder users = by_active(users) users = by_external_identity(users) users = by_external(users) + users = by_created_at(users) users end diff --git a/app/models/concerns/created_at_filterable.rb b/app/models/concerns/created_at_filterable.rb new file mode 100644 index 00000000000..e8a3e41203d --- /dev/null +++ b/app/models/concerns/created_at_filterable.rb @@ -0,0 +1,12 @@ +module CreatedAtFilterable + extend ActiveSupport::Concern + + included do + scope :created_before, ->(date) { where(scoped_table[:created_at].lteq(date)) } + scope :created_after, ->(date) { where(scoped_table[:created_at].gteq(date)) } + + def self.scoped_table + arel_table.alias(table_name) + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb index 01f985823e1..400bb55d2f0 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -10,6 +10,7 @@ class Issue < ActiveRecord::Base include FasterCacheKeys include RelativePositioning include IgnorableColumn + include CreatedAtFilterable ignore_column :position @@ -50,8 +51,6 @@ class Issue < ActiveRecord::Base scope :order_due_date_asc, -> { reorder('issues.due_date IS NULL, issues.due_date ASC') } scope :order_due_date_desc, -> { reorder('issues.due_date IS NULL, issues.due_date DESC') } - scope :created_after, -> (datetime) { where("created_at >= ?", datetime) } - scope :preload_associations, -> { preload(:labels, project: :namespace) } after_save :expire_etag_cache diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 6ea774470af..815c5b43406 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -5,6 +5,7 @@ class MergeRequest < ActiveRecord::Base include Referable include Sortable include IgnorableColumn + include CreatedAtFilterable ignore_column :position @@ -14,7 +15,7 @@ class MergeRequest < ActiveRecord::Base has_many :merge_request_diffs has_one :merge_request_diff, - -> { order('merge_request_diffs.id DESC') } + -> { order('merge_request_diffs.id DESC') }, inverse_of: :merge_request belongs_to :head_pipeline, foreign_key: "head_pipeline_id", class_name: "Ci::Pipeline" diff --git a/app/models/project.rb b/app/models/project.rb index 74c15d2508b..d0e02e4e585 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -536,6 +536,11 @@ class Project < ActiveRecord::Base ProjectCacheWorker.perform_async(self.id) end + remove_import_data + end + + # This method is overriden in EE::Project model + def remove_import_data import_data&.destroy end diff --git a/app/models/user.rb b/app/models/user.rb index 4411a06d429..4b01c2f19f0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -12,6 +12,7 @@ class User < ActiveRecord::Base include TokenAuthenticatable include IgnorableColumn include FeatureGate + include CreatedAtFilterable DEFAULT_NOTIFICATION_LEVEL = :participating diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 9149b8e7fb9..843c71af466 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -107,8 +107,7 @@ = select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2" %hr = button_tag 'Add users to group', class: "btn btn-create" - - = render 'shared/members/requests', membership_source: @group, requesters: @requesters + = render 'shared/members/requests', membership_source: @group, requesters: @requesters, force_mobile_view: true .panel.panel-default .panel-heading @@ -117,7 +116,7 @@ %span.badge= @group.members.size .pull-right = link_to icon('pencil-square-o', text: 'Manage access'), polymorphic_url([@group, :members]), class: "btn btn-xs" - %ul.well-list.group-users-list.content-list + %ul.well-list.group-users-list.content-list.members-list = render partial: 'shared/members/member', collection: @members, as: :member, locals: { show_controls: false } .panel-footer = paginate @members, param_name: 'members_page', theme: 'gitlab' diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index fb9057b2db5..7b1b15cfeb8 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -160,12 +160,12 @@ .pull-right = link_to admin_group_path(@group), class: 'btn btn-xs' do = icon('pencil-square-o', text: 'Manage access') - %ul.well-list.content-list + %ul.well-list.content-list.members-list = render partial: 'shared/members/member', collection: @group_members, as: :member, locals: { show_controls: false } .panel-footer = paginate @group_members, param_name: 'group_members_page', theme: 'gitlab' - = render 'shared/members/requests', membership_source: @project, requesters: @requesters + = render 'shared/members/requests', membership_source: @project, requesters: @requesters, force_mobile_view: true .panel.panel-default .panel-heading @@ -174,7 +174,7 @@ %span.badge= @project.users.size .pull-right = link_to icon('pencil-square-o', text: 'Manage access'), polymorphic_url([@project, :members]), class: "btn btn-xs" - %ul.well-list.project_members.content-list + %ul.well-list.project_members.content-list.members-list = render partial: 'shared/members/member', collection: @project_members, as: :member, locals: { show_controls: false } .panel-footer = paginate @project_members, param_name: 'project_members_page', theme: 'gitlab' diff --git a/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml new file mode 100644 index 00000000000..0319838bdb4 --- /dev/null +++ b/app/views/dashboard/projects/_blank_state_admin_welcome.html.haml @@ -0,0 +1,33 @@ +.row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("add_new_user", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Add user + %p.blank-state-text + Add your team members and others to GitLab. + = link_to new_admin_user_path, class: "btn btn-new" do + New user + +.row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("configure_server", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Configure GitLab + %p.blank-state-text + Make adjustments to how your GitLab instance is set up. + = link_to admin_root_path, class: "btn btn-new" do + Configure + +- if current_user.can_create_group? + .row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("add_new_group", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Create a group + %p.blank-state-text + Groups are a great way to organise projects and people. + = link_to new_group_path, class: "btn btn-new" do + New group diff --git a/app/views/dashboard/projects/_blank_state_welcome.html.haml b/app/views/dashboard/projects/_blank_state_welcome.html.haml new file mode 100644 index 00000000000..a079f0ac1a4 --- /dev/null +++ b/app/views/dashboard/projects/_blank_state_welcome.html.haml @@ -0,0 +1,48 @@ +- public_project_count = ProjectsFinder.new(current_user: current_user).execute.count + +- if current_user.can_create_group? + .row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("add_new_group", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Create a group for several dependent projects. + %p.blank-state-text + Groups are the best way to manage projects and members. + = link_to new_group_path, class: "btn btn-new" do + New group + +.row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("add_new_project", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Create a project + %p.blank-state-text + - if current_user.can_create_project? + You don't have access to any projects right now. + You can create up to + %strong= number_with_delimiter(current_user.projects_limit) + = succeed "." do + = "project".pluralize(current_user.projects_limit) + - else + If you are added to a project, it will be displayed here. + - if current_user.can_create_project? + = link_to new_project_path, class: "btn btn-new" do + New project + +- if public_project_count > 0 + .row.blank-state.clearfix + .col-md-1.col-md-offset-3.blank-state-icon + = custom_icon("globe", size: 50) + .col-md-5.blank-state-body + %h3.blank-state-title + Explore public projects + %p.blank-state-text + There are + = number_with_delimiter(public_project_count) + public projects on this server. + Public projects are an easy way to allow + everyone to have read-only access. + = link_to trending_explore_projects_path, class: "btn btn-new" do + Browse projects diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml index 8843d4e7c84..94af033c1e3 100644 --- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml @@ -1,47 +1,12 @@ -- publicish_project_count = ProjectsFinder.new(current_user: current_user).execute.count -.blank-state.blank-state-welcome - %h2.blank-state-welcome-title - Welcome to GitLab - %p.blank-state-text - Code, test, and deploy together - -- if current_user.can_create_group? - .blank-state - .blank-state-icon - = custom_icon("group", size: 50) - %h3.blank-state-title - You can create a group for several dependent projects. - %p.blank-state-text - Groups are the best way to manage projects and members. - = link_to new_group_path, class: "btn btn-new" do - New group - -.blank-state - .blank-state-icon - = custom_icon("project", size: 50) - %h3.blank-state-title - You don't have access to any projects right now - %p.blank-state-text - - if current_user.can_create_project? - You can create up to - %strong= number_with_delimiter(current_user.projects_limit) - = succeed "." do - = "project".pluralize(current_user.projects_limit) - - else - If you are added to a project, it will be displayed here. - - if current_user.can_create_project? - = link_to new_project_path, class: "btn btn-new" do - New project - -- if publicish_project_count > 0 - .blank-state - .blank-state-icon - = icon("globe") - %h3.blank-state-title - There are - = number_with_delimiter(publicish_project_count) - public projects on this server. - %p.blank-state-text - Public projects are an easy way to allow everyone to have read-only access. - = link_to trending_explore_projects_path, class: "btn btn-new" do - Browse projects +.row.blank-state-parent-container + .section-container + .container.section-body.section-welcome{ class: "#{ 'section-admin-welcome' if current_user.admin? }" } + .blank-state.blank-state-welcome + %h2.blank-state-welcome-title + Welcome to GitLab + %p.blank-state-text + Code, test, and deploy together + - if current_user.admin? + = render "blank_state_admin_welcome" + - else + = render "blank_state_welcome" diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 2e4e4511bb6..ad9d5562ded 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -27,6 +27,6 @@ Members with access to %strong= @group.name %span.badge= @members.total_count - %ul.content-list + %ul.content-list.members-list = render partial: 'shared/members/member', collection: @members, as: :member = paginate @members, theme: 'gitlab' diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index 1f18490594b..e71d58ec26d 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -11,5 +11,5 @@ %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } = icon("search") = render 'shared/members/sort_dropdown' - %ul.content-list + %ul.content-list.members-list = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/shared/icons/_add_new_group.svg b/app/views/shared/icons/_add_new_group.svg new file mode 100644 index 00000000000..ecd52c5e99f --- /dev/null +++ b/app/views/shared/icons/_add_new_group.svg @@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"> + <g fill="none" fill-rule="evenodd"> + <path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/> + <path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/> + <path fill="#E1DBF2" fill-rule="nonzero" d="M59.65 32.65H60l-2-2.42-2 2.4-2-2.4-2 2.4-2-2.4-2 2.4-2-2.4-2 2.42h.77C45.57 34.6 46 36.75 46 39c0 2.84-.7 5.5-1.92 7.86 1.97 2.28 4.83 3.64 7.92 3.64 5.8 0 10.5-4.74 10.5-10.6 0-2.8-1.08-5.36-2.85-7.25zM43.18 29.6c2.4-2.1 5.52-3.3 8.82-3.3 7.46 0 13.5 6.1 13.5 13.6S59.46 53.5 52 53.5c-3.68 0-7.1-1.5-9.6-4.04C39.3 53.44 34.44 56 29 56c-9.4 0-17-7.6-17-17s7.6-17 17-17c3.22 0 6.23.9 8.8 2.45 2.13 1.3 3.97 3.05 5.38 5.16zM17 34c-.65 1.54-1 3.23-1 5 0 7.18 5.82 13 13 13s13-5.82 13-13c0-1.77-.35-3.46-1-5h-9c-.53 0-1.04-.2-1.4-.6L29 31.84l-1.6 1.58c-.36.4-.87.6-1.4.6h-9zm21.38-4c-2.4-2.5-5.76-4-9.38-4-3.62 0-6.98 1.5-9.38 4h5.55l2.42-2.4c.74-.8 2-.8 2.8 0l2.4 2.4h5.54z"/> + <path fill="#6B4FBB" d="M47.6 42.32c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zm8.8 0c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zM25 44h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-1c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/> + </g> +</svg> diff --git a/app/views/shared/icons/_add_new_project.svg b/app/views/shared/icons/_add_new_project.svg new file mode 100644 index 00000000000..3c1e15453df --- /dev/null +++ b/app/views/shared/icons/_add_new_project.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M30 24a4 4 0 0 0-4 4v22a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V28a4 4 0 0 0-4-4H30zm0-4h18a8 8 0 0 1 8 8v22a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V28a8 8 0 0 1 8-8z"/><path fill="#FC6D26" d="M33 30h8a2 2 0 1 1 0 4h-8a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4z"/></g></svg>
\ No newline at end of file diff --git a/app/views/shared/icons/_add_new_user.svg b/app/views/shared/icons/_add_new_user.svg new file mode 100644 index 00000000000..0ad40498d7b --- /dev/null +++ b/app/views/shared/icons/_add_new_user.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"> + <g fill="none" fill-rule="evenodd"> + <path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/> + <path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/> + <path fill="#E1DBF2" d="M44 31l-2.5-3-2.5 3-2.5-3-2.5 3-2.5-3-2.5 3h-2.72c2.65-4.2 7.36-7 12.72-7s10.07 2.8 12.72 7H49l-2.5-3-2.5 3z"/> + <path fill="#E1DBF2" fill-rule="nonzero" d="M39 57c-9.4 0-17-7.6-17-17s7.6-17 17-17 17 7.6 17 17-7.6 17-17 17zm0-4c7.18 0 13-5.82 13-13s-5.82-13-13-13-13 5.82-13 13 5.82 13 13 13z"/> + <path fill="#6B4FBB" d="M35 45h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/> + </g> +</svg> diff --git a/app/views/shared/icons/_configure_server.svg b/app/views/shared/icons/_configure_server.svg new file mode 100644 index 00000000000..b1137b7ec94 --- /dev/null +++ b/app/views/shared/icons/_configure_server.svg @@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"> + <g fill="none" fill-rule="evenodd"> + <path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/> + <path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/> + <path fill="#FEE1D3" fill-rule="nonzero" d="M24.92 35.15c-1.72-1.4-1.98-3.9-.6-5.63l1.26-1.55c1.4-1.72 3.9-2 5.63-.6l.7.56c.7-.4 1.4-.73 2.1-1V26c0-2.2 1.8-4 4-4h2c2.2 0 4 1.8 4 4v.92c.8.28 1.5.62 2.1 1l.7-.55c1.7-1.4 4.3-1.12 5.7.6l1.3 1.55c1.4 1.72 1.2 4.23-.6 5.63l-.7.6c.3.74.4 1.5.5 2.3l.9.2c2.2.5 3.5 2.64 3 4.8L56.4 45c-.5 2.15-2.64 3.5-4.8 3l-.88-.2c-.44.63-.92 1.24-1.46 1.8l.4.82c.9 1.98.1 4.38-1.9 5.35l-1.8.87c-2 .97-4.37.15-5.34-1.84l-.46-.85c-.34.03-.74.05-1.13.05-.4 0-.8-.02-1.2-.05l-.4.85c-.95 2-3.34 2.8-5.33 1.84l-1.8-.87c-1.97-.97-2.8-3.37-1.83-5.35l.4-.8c-.54-.58-1.02-1.2-1.46-1.83l-.8.2c-2.2.5-4.3-.9-4.8-3l-.4-2c-.5-2.2.85-4.3 3-4.8l.9-.2c.1-.8.3-1.6.5-2.3l-.7-.6zm4.95.77c-.53 1.2-.83 2.47-.87 3.8-.02.9-.66 1.68-1.55 1.9l-2.32.53.45 1.94 2.3-.6c.9-.2 1.8.2 2.23 1 .7 1.1 1.5 2.2 2.5 3 .7.6.9 1.6.5 2.4l-1 2.1 1.8.9 1.1-2.1c.4-.8 1.3-1.3 2.2-1.1.7.1 1.3.2 2 .2s1.3-.1 2-.2c.9-.2 1.8.3 2.2 1.1l1 2.1 1.8-.9-1.2-2c-.4-.8-.2-1.8.5-2.4 1-.85 1.84-1.88 2.45-3.05.4-.82 1.33-1.24 2.2-1.04l2.33.54.45-1.95-2.32-.54c-.9-.2-1.52-.97-1.54-1.88-.03-1.4-.33-2.6-.86-3.8-.4-.9-.2-1.8.5-2.4l1.9-1.5-1.3-1.6-1.8 1.5c-.8.5-1.8.6-2.5 0-1.1-.8-2.3-1.4-3.5-1.7-.9-.2-1.5-1-1.5-1.9V26h-2v2.38c0 .9-.6 1.7-1.5 1.93-1.3.4-2.5 1-3.5 1.7-.8.6-1.8.6-2.5 0l-1.9-1.5-1.26 1.6 1.8 1.5c.7.6.94 1.6.6 2.4z"/> + <path fill="#FC6D26" fill-rule="nonzero" d="M39 46c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/> + </g> +</svg> diff --git a/app/views/shared/icons/_globe.svg b/app/views/shared/icons/_globe.svg new file mode 100644 index 00000000000..c2daae5f317 --- /dev/null +++ b/app/views/shared/icons/_globe.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" d="M30.24 27.823A14.98 14.98 0 0 0 24 40c0 2.549.636 4.949 1.757 7.051-.297-2.684.644-4.026 2.823-4.026 3.707 0 2.462 5.365 4.473 5.761 2.01.396 4.175.396 4.267 3.29.04 1.257-.265 2.157-.917 2.7a15.095 15.095 0 0 0 8.555-1.006c.035-1.91.303-4.941 2.21-5.61 2.373-.833-.55-1.431.734-3.368 1.17-1.762-3.297-5.2 0-4.832 3.477.388 5.044-.816 6.024-1.456a14.903 14.903 0 0 0-1.373-4.94c-.873.4-2.19.465-3.702-.538-.757-.502-1.084-3.944-2.107-3.944-3.823 0-4.065 3.17-5.994 3.944-1.076.431-4.193 3.773-5.614 3.596-1.126-.14-1.071-4.417-2.45-5.166-1.359-.738-2.174-1.948-2.447-3.633zM39 59c-10.493 0-19-8.507-19-19s8.507-19 19-19 19 8.507 19 19-8.507 19-19 19z"/></g></svg>
\ No newline at end of file diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index a5aa768b1b2..951b4dd7b36 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -1,5 +1,6 @@ - show_roles = local_assigns.fetch(:show_roles, true) - show_controls = local_assigns.fetch(:show_controls, true) +- force_mobile_view = local_assigns.fetch(:force_mobile_view, false) - user = local_assigns.fetch(:user, member.user) - source = member.source - can_admin_member = can?(current_user, action_member_permission(:update, member), member) @@ -8,45 +9,53 @@ %span.list-item-name - if user = image_tag avatar_icon(user, 40), class: "avatar s40", alt: '' - %strong - = link_to user.name, user_path(user) - %span.cgray= user.to_reference + .user-info + = link_to user.name, user_path(user), class: 'member' + %span.cgray= user.to_reference - - if user == current_user - %span.label.label-success.prepend-left-5 It's you + - if user == current_user + %span.label.label-success.prepend-left-5 It's you - - if user.blocked? - %label.label.label-danger - %strong Blocked + - if user.blocked? + %label.label.label-danger + %strong Blocked - - if source.instance_of?(Group) && source != @group - · - = link_to source.full_name, source, class: "member-group-link" + - if source.instance_of?(Group) && source != @group + · + = link_to source.full_name, source, class: "member-group-link" - .hidden-xs.cgray - - if member.request? - Requested - = time_ago_with_tooltip(member.requested_at) - - else - Joined #{time_ago_with_tooltip(member.created_at)} - - if member.expires? - · - %span{ class: "#{"text-warning" if member.expires_soon?} has-tooltip", title: member.expires_at.to_time.in_time_zone.to_s(:medium) } - Expires in #{distance_of_time_in_words_to_now(member.expires_at)} + .cgray + - if member.request? + Requested + = time_ago_with_tooltip(member.requested_at) + - else + Joined #{time_ago_with_tooltip(member.created_at)} + - if member.expires? + · + %span{ class: "#{"text-warning" if member.expires_soon?} has-tooltip", title: member.expires_at.to_time.in_time_zone.to_s(:medium) } + Expires in #{distance_of_time_in_words_to_now(member.expires_at)} - else = image_tag avatar_icon(member.invite_email, 40), class: "avatar s40", alt: '' - %strong= member.invite_email - .cgray - Invited - - if member.created_by - by - = link_to member.created_by.name, user_path(member.created_by) - = time_ago_with_tooltip(member.created_at) + .user-info + .member= member.invite_email + .cgray + Invited + - if member.created_by + by + = link_to member.created_by.name, user_path(member.created_by) + = time_ago_with_tooltip(member.created_at) - if show_roles - current_resource = @project || @group .controls.member-controls - if show_controls && member.source == current_resource + + - if member.invite? && can?(current_user, action_member_permission(:admin, member), member.source) + = link_to icon('paper-plane'), polymorphic_path([:resend_invite, member]), + method: :post, + class: 'btn btn-default prepend-left-10 hidden-xs', + title: 'Resend invite' + - if user != current_user && can_admin_member = form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f| = f.hidden_field :access_level @@ -75,13 +84,17 @@ - if member.invite? && can?(current_user, action_member_permission(:admin, member), member.source) = link_to 'Resend invite', polymorphic_path([:resend_invite, member]), method: :post, - class: 'btn btn-default prepend-left-10' + class: 'btn btn-default prepend-left-10 visible-xs-block' - elsif member.request? && can_admin_member - = link_to icon('check inverse'), polymorphic_path([:approve_access_request, member]), + = link_to polymorphic_path([:approve_access_request, member]), method: :post, class: 'btn btn-success prepend-left-10', - title: 'Grant access' + title: 'Grant access' do + %span{ class: ('visible-xs-block' unless force_mobile_view) } + Grant access + - unless force_mobile_view + = icon('check inverse', class: 'hidden-xs') - if can?(current_user, action_member_permission(:destroy, member), member) - if current_user == user @@ -96,8 +109,9 @@ data: { confirm: remove_member_message(member) }, class: 'btn btn-remove prepend-left-10', title: remove_member_title(member) do - %span.visible-xs-block + %span{ class: ('visible-xs-block' unless force_mobile_view) } Delete - = icon('trash', class: 'hidden-xs') + - unless force_mobile_view + = icon('trash', class: 'hidden-xs') - else %span.member-access-text= member.human_access diff --git a/app/views/shared/members/_requests.html.haml b/app/views/shared/members/_requests.html.haml index 92f6e7428ae..09b9944082f 100644 --- a/app/views/shared/members/_requests.html.haml +++ b/app/views/shared/members/_requests.html.haml @@ -1,8 +1,10 @@ +- force_mobile_view = local_assigns.fetch(:force_mobile_view, false) + - if requesters.any? - .panel.panel-default.prepend-top-default + .panel.panel-default.prepend-top-default{ class: ('panel-mobile' if force_mobile_view ) } .panel-heading Users requesting access to %strong= membership_source.name %span.badge= requesters.size - %ul.content-list - = render partial: 'shared/members/member', collection: requesters, as: :member + %ul.content-list.members-list + = render partial: 'shared/members/member', collection: requesters, as: :member, locals: { force_mobile_view: force_mobile_view } diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb index e85e221d353..45ce49bb5c0 100644 --- a/app/workers/background_migration_worker.rb +++ b/app/workers/background_migration_worker.rb @@ -2,18 +2,34 @@ class BackgroundMigrationWorker include Sidekiq::Worker include DedicatedSidekiqQueue - # Schedules a number of jobs in bulk + # Enqueues a number of jobs in bulk. # # The `jobs` argument should be an Array of Arrays, each sub-array must be in # the form: # # [migration-class, [arg1, arg2, ...]] - def self.perform_bulk(*jobs) + def self.perform_bulk(jobs) Sidekiq::Client.push_bulk('class' => self, 'queue' => sidekiq_options['queue'], 'args' => jobs) end + # Schedules multiple jobs in bulk, with a delay. + # + def self.perform_bulk_in(delay, jobs) + now = Time.now.to_i + schedule = now + delay.to_i + + if schedule <= now + raise ArgumentError, 'The schedule time must be in the future!' + end + + Sidekiq::Client.push_bulk('class' => self, + 'queue' => sidekiq_options['queue'], + 'args' => jobs, + 'at' => schedule) + end + # Performs the background migration. # # See Gitlab::BackgroundMigration.perform for more information. |