diff --git a/app/assets/javascripts/user_tabs.js b/app/assets/javascripts/user_tabs.js index 5db0d936ad84c878c9307a1f5cd4bb0171e2d43b..632ae768ee3174c9a701283f5168a25ccf5e9c17 100644 --- a/app/assets/javascripts/user_tabs.js +++ b/app/assets/javascripts/user_tabs.js @@ -67,11 +67,14 @@ content on the Users#show page. this.action = action || this.defaultAction; this.$parentEl = $(parentEl) || $(document); this._location = window.location; + this.$parentEl.find('.nav-links a') .each((i, navLink) => { this.loaded[$(navLink).attr('data-action')] = false; }); + this.actions = Object.keys(this.loaded); + this.initEmptyStates(); this.bindEvents(); if (this.action === 'show') { @@ -90,6 +93,17 @@ content on the Users#show page. this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper); } + initEmptyStates() { + this.emptyStates = { + snippets: document.querySelector('#js-user-snippets-empty-state'), + }; + } + + showEmptyState(tabSelector, action) { + if (this.emptyStates[action]) this.emptyStates[action].classList.remove('hidden'); + this.loaded[action] = true; + } + changeProjectsPage(e) { e.preventDefault(); @@ -125,6 +139,7 @@ content on the Users#show page. } loadTab(source, action) { + if (this.emptyStates[action]) this.emptyStates[action].classList.add('hidden'); return $.ajax({ beforeSend: () => this.toggleLoading(true), complete: () => this.toggleLoading(false), @@ -133,6 +148,9 @@ content on the Users#show page. url: source, success: (data) => { const tabSelector = `div#${action}`; + + if (!data.html) return this.showEmptyState(tabSelector, action); + this.$parentEl.find(tabSelector).html(data.html); this.loaded[action] = true; return gl.utils.localTimeAgo($('.js-timeago', tabSelector)); diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 524252629254e3b1f8a259c8ed1054d42ee1f50c..331e9f8bc0699429a587262f6ef425d3a09c434a 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -292,6 +292,10 @@ } @media(min-width: $screen-xs-max) { + &.snippets .text-content { + margin-top: 100px; + } + &.merge-requests .text-content { margin-top: 40px; } diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a452bbba422bbf9803b361aef7acece2630a1007..a61a3d7afc5eda1ca4d51b0f80de6916a04f7443 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -65,7 +65,7 @@ def snippets format.html { render 'show' } format.json do render json: { - html: view_to_html_string("snippets/_snippets", collection: @snippets) + html: @snippets.blank? ? nil : view_to_html_string("snippets/_snippets", collection: @snippets) } end end diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 85cbe0bf0e6e7a6e754c8a0b9413c6be95c1ab7b..305359eff081ff82f7104d72fcb5c4874e78885d 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -1,12 +1,15 @@ - page_title "Snippets" - header_title "Snippets", dashboard_snippets_path -= render 'dashboard/snippets_head' -= render partial: 'snippets/snippets_scope_menu', locals: { include_private: true } +- if current_user.snippets.exists? + = render 'dashboard/snippets_head' + = render partial: 'snippets/snippets_scope_menu', locals: { include_private: true } -.visible-xs -   - = link_to new_snippet_path, class: "btn btn-new btn-block", title: "New snippet" do - New snippet + .visible-xs +   + = link_to new_snippet_path, class: "btn btn-new btn-block", title: "New snippet" do + New snippet -= render partial: 'snippets/snippets', locals: { link_project: true } + = render partial: 'snippets/snippets', locals: { link_project: true } +- else + = render 'shared/empty_states/snippets', button_path: new_snippet_path diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index 84e05cd6d88b49c1fd34282af7dc47a6b03d09d2..2c673b1b099b76de7f4e6a916364e86e91cd4ddb 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -1,19 +1,22 @@ - page_title "Snippets" -- if current_user - .top-area - - include_private = @project.team.member?(current_user) || current_user.admin? - = render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private } +- if @snippets.exists? + - if current_user + .top-area + - include_private = @project.team.member?(current_user) || current_user.admin? + = render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private } - .nav-controls.hidden-xs - - if can?(current_user, :create_project_snippet, @project) - = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New snippet" do - New snippet + .nav-controls.hidden-xs + - if can?(current_user, :create_project_snippet, @project) + = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New snippet" do + New snippet -- if can?(current_user, :create_project_snippet, @project) - .visible-xs -   - = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new btn-block", title: "New snippet" do - New snippet + - if can?(current_user, :create_project_snippet, @project) + .visible-xs +   + = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new btn-block", title: "New snippet" do + New snippet -= render 'snippets/snippets' + = render 'snippets/snippets' +- else + = render 'shared/empty_states/snippets', button_path: new_namespace_project_snippet_path(@project.namespace, @project) diff --git a/app/views/shared/empty_states/_snippets.html.haml b/app/views/shared/empty_states/_snippets.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..4c289923a97db4791a2b46e82ab1c1e9755cfc56 --- /dev/null +++ b/app/views/shared/empty_states/_snippets.html.haml @@ -0,0 +1,15 @@ +- button_path = local_assigns.fetch(:button_path, false) + +.row.empty-state.snippets + .col-xs-12.pull-right{ class: "#{'col-sm-6' if button_path}" } + .svg-content + = render 'shared/empty_states/icons/snippets.svg' + .col-xs-12{ class: "#{'col-sm-6' if button_path}" } + .text-content + - if button_path + %h4 + Snippets are small pieces of code or notes that you want to keep. + They can be either public or private. + = link_to 'New snippet', button_path, class: 'btn btn-new', title: 'New snippet', id: 'new_snippet_link' + - else + %h4.text-center There are no snippets to show. diff --git a/app/views/shared/empty_states/icons/_snippets.svg b/app/views/shared/empty_states/icons/_snippets.svg new file mode 100644 index 0000000000000000000000000000000000000000..105f25931a83f3e2b2ac065437221645562c177a --- /dev/null +++ b/app/views/shared/empty_states/icons/_snippets.svg @@ -0,0 +1 @@ + diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml index ac3701233ad1e8411391a9c190a65c3ec2e40462..b5be6b3e7aa1d4bfb8e573c8ee07bba98dbb0d36 100644 --- a/app/views/snippets/_snippets.html.haml +++ b/app/views/snippets/_snippets.html.haml @@ -1,14 +1,14 @@ - remote = local_assigns.fetch(:remote, false) - link_project = local_assigns.fetch(:link_project, false) -.snippets-list-holder - %ul.content-list - = render partial: 'shared/snippets/snippet', collection: @snippets, locals: { link_project: link_project } - - if @snippets.empty? - %li - .nothing-here-block Nothing here. +- if @snippets.exists? + .snippets-list-holder + %ul.content-list + = render partial: 'shared/snippets/snippet', collection: @snippets, locals: { link_project: link_project } - = paginate @snippets, theme: 'gitlab', remote: remote + = paginate @snippets, theme: 'gitlab', remote: remote -:javascript - gl.SnippetsList(); + :javascript + gl.SnippetsList(); +- else + = render 'shared/empty_states/snippets' diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 969ea7ab9e60ff911e03ae600a3492c8e1a2a358..8427cec9ef6c3cf8cb00b16d5b0f8004bb8e95ff 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -126,6 +126,8 @@ #snippets.tab-pane -# This tab is always loaded via AJAX + #js-user-snippets-empty-state.hidden + = render 'shared/empty_states/snippets', button_path: new_snippet_path .loading-status = spinner diff --git a/changelogs/unreleased/20847-getting-started-better-empty-state-for-snippets-view.yml b/changelogs/unreleased/20847-getting-started-better-empty-state-for-snippets-view.yml new file mode 100644 index 0000000000000000000000000000000000000000..3d34762a0e0fd209b1f19e70f36069094e154c27 --- /dev/null +++ b/changelogs/unreleased/20847-getting-started-better-empty-state-for-snippets-view.yml @@ -0,0 +1,4 @@ +--- +title: Added snippets empty state +merge_request: 7645 +author: diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index 4c9adcabe34330de14b31b787afa1b3ee3f2927d..1d4d453f1dc0fe0adf0192a16a4838c90002fbd4 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -42,7 +42,7 @@ find('body').native.send_keys([:shift, 'S']) - expect(page).to have_selector('.snippets-list-holder') + expect(page).to have_content('There are no snippets to show.') end end