diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js index 62f49769f4d4a7e126ef8fd9540dd33c5b4aa5fb..85ca2228cdfec23c35b461ee1aef51e2c9973bb1 100644 --- a/app/assets/javascripts/pages/users/user_tabs.js +++ b/app/assets/javascripts/pages/users/user_tabs.js @@ -209,7 +209,7 @@ export default class UserTabs { }); UserTabs.renderMostRecentBlocks('#js-overview .projects-block', { - requestParams: { limit: 10, skip_pagination: true, skip_namespace: true, compact_mode: true }, + requestParams: { limit: 3, skip_pagination: true, skip_namespace: true, card_mode: true }, }); this.loaded.overview = true; diff --git a/app/assets/javascripts/profile/components/profile_tabs.vue b/app/assets/javascripts/profile/components/profile_tabs.vue index e24167eb4fa713defd1aec55ef1791a64495357a..a15794ac07d517454862c2b0efa53dbf364f3d16 100644 --- a/app/assets/javascripts/profile/components/profile_tabs.vue +++ b/app/assets/javascripts/profile/components/profile_tabs.vue @@ -81,7 +81,7 @@ export default { }, async mounted() { try { - const response = await getUserProjects(this.userId, { per_page: 10 }); + const response = await getUserProjects(this.userId, { per_page: 3 }); this.personalProjects = convertObjectPropsToCamelCase(response.data, { deep: true }).map( (project) => { // This API does not return the `visibility` key if user is signed out. diff --git a/app/assets/stylesheets/page_bundles/projects.scss b/app/assets/stylesheets/page_bundles/projects.scss index bfa350097fabab45ee355e00707fb59054ca0df3..8b950cb168378ba0d60b68ff45ae55cbe9171fe6 100644 --- a/app/assets/stylesheets/page_bundles/projects.scss +++ b/app/assets/stylesheets/page_bundles/projects.scss @@ -324,14 +324,6 @@ @include media-breakpoint-up(lg) { @include gl-justify-content-start; @include gl-pr-9; - - &:not(.with-pipeline-status) { - .icon-wrapper:first-of-type { - @include media-breakpoint-up(lg) { - @include gl-ml-7; - } - } - } } } @@ -568,3 +560,8 @@ } } } + +.projects-list .description p { + @include gl-line-clamp-2; + margin-bottom: 0; +} diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 88a8851607b21a886cc053569f8d2ac7211d567b..0d8a14acbd0c721f2ab70020f2456d4fdbbd5dae 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -143,13 +143,14 @@ def present_projects skip_pagination = Gitlab::Utils.to_boolean(params[:skip_pagination]) skip_namespace = Gitlab::Utils.to_boolean(params[:skip_namespace]) compact_mode = Gitlab::Utils.to_boolean(params[:compact_mode]) + card_mode = Gitlab::Utils.to_boolean(params[:card_mode]) respond_to do |format| format.html { render 'show' } format.json do projects = yield - pager_json("shared/projects/_list", projects.count, projects: projects, skip_pagination: skip_pagination, skip_namespace: skip_namespace, compact_mode: compact_mode) + pager_json("shared/projects/_list", projects.count, projects: projects, skip_pagination: skip_pagination, skip_namespace: skip_namespace, compact_mode: compact_mode, card_mode: card_mode) end end end diff --git a/app/views/shared/projects/_archived.html.haml b/app/views/shared/projects/_archived.html.haml index 018bf137cc6c46689a5f968630861a1085f5f79b..d1d0f1b7ee6d11fa5b5a8ed48038f69dff2be876 100644 --- a/app/views/shared/projects/_archived.html.haml +++ b/app/views/shared/projects/_archived.html.haml @@ -1,2 +1,2 @@ - if project.archived - = gl_badge_tag _('archived'), { variant: :warning }, { class: 'gl-display-flex gl-ml-3' } + = gl_badge_tag _('archived'), { variant: :warning } diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index 74c325383a1a770acc4eabbd7a9446c4cf472e38..e56edcee790d0058a8a9ba00f00a9cb9d1c80810 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -10,7 +10,8 @@ - remote = false unless local_assigns[:remote] == true - skip_pagination = false unless local_assigns[:skip_pagination] == true - compact_mode = false unless local_assigns[:compact_mode] == true -- css_classes = "#{'compact' if compact_mode} #{'explore' if explore_projects_tab?}" +- card_mode = local_assigns[:card_mode] == true +- css_classes = "#{'compact' if compact_mode} #{'gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-gap-4 gl-overflow-x-auto' if card_mode} #{'explore' if explore_projects_tab?}" - contributed_projects_current_user_empty_message_header = s_('UserProfile|Explore public groups to find projects to contribute to.') - contributed_projects_visitor_empty_message = s_('UserProfile|This user hasn\'t contributed to any projects') - starred_projects_illustration_path = 'illustrations/empty-state/empty-projects-starred-md.svg' @@ -33,14 +34,31 @@ - load_pipeline_status(projects) if pipeline_status - load_max_project_member_accesses(projects) # Prime cache used in shared/projects/project view rendered below - load_catalog_resources(projects) - %ul.projects-list.gl-text-secondary.gl-w-full.gl-my-2{ class: css_classes } - - projects.each_with_index do |project, i| - - css_class = (i >= projects_limit) || project.pending_delete? ? 'hide' : nil - = render "shared/projects/project", project: project, skip_namespace: skip_namespace, - avatar: avatar, stars: stars, css_class: css_class, use_creator_avatar: use_creator_avatar, - forks: able_to_see_forks_count?(project, user), show_last_commit_as_description: show_last_commit_as_description, - user: user, merge_requests: able_to_see_merge_requests?(project, user), issues: able_to_see_issues?(project, user), - pipeline_status: pipeline_status, compact_mode: compact_mode + - project_count = 0 + - if card_mode + .projects-list.gl-text-secondary.gl-w-full{ class: css_classes } + - projects.each_with_index do |project, i| + - break if project_count >= projects_limit + - next if project.pending_delete? + - project_count += 1 + + = render "shared/projects/project_card", project: project, skip_namespace: skip_namespace, + avatar: avatar, stars: stars, use_creator_avatar: use_creator_avatar, + forks: able_to_see_forks_count?(project, user), show_last_commit_as_description: show_last_commit_as_description, + user: user, merge_requests: able_to_see_merge_requests?(project, user), issues: able_to_see_issues?(project, user), + pipeline_status: pipeline_status, compact_mode: compact_mode + - else + %ul.projects-list.gl-text-secondary.gl-w-full.gl-my-2{ class: css_classes } + - projects.each_with_index do |project, i| + - break if project_count >= projects_limit + - next if project.pending_delete? + - project_count += 1 + + = render "shared/projects/project", project: project, skip_namespace: skip_namespace, + avatar: avatar, stars: stars, use_creator_avatar: use_creator_avatar, + forks: able_to_see_forks_count?(project, user), show_last_commit_as_description: show_last_commit_as_description, + user: user, merge_requests: able_to_see_merge_requests?(project, user), issues: able_to_see_issues?(project, user), + pipeline_status: pipeline_status, compact_mode: compact_mode = paginate_collection(projects, remote: remote) unless skip_pagination - else - if @contributed_projects diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 5bb15c2f5ca56f4123ecdc17db11e5a4fb095cb9..25acc7092a4a2fa18faa0aa354dd8bcbe1b851b6 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -1,28 +1,32 @@ -- avatar = true unless local_assigns[:avatar] == false -- stars = true unless local_assigns[:stars] == false -- forks = true unless local_assigns[:forks] == false -- merge_requests = true unless local_assigns[:merge_requests] == false -- issues = true unless local_assigns[:issues] == false -- pipeline_status = true unless local_assigns[:pipeline_status] == false -- skip_namespace = false unless local_assigns[:skip_namespace] == true -- access = max_project_member_access(project) -- compact_mode = false unless local_assigns[:compact_mode] == true +- avatar = local_assigns[:avatar] != false +- stars = local_assigns[:stars] != false +- forks = local_assigns[:forks] != false +- merge_requests = local_assigns[:merge_requests] != false +- issues = local_assigns[:issues] != false +- pipeline_status = local_assigns[:pipeline_status] != false +- skip_namespace = local_assigns[:skip_namespace] == true +- compact_mode = local_assigns[:compact_mode] == true +- use_creator_avatar = local_assigns[:use_creator_avatar] == true - show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && can_show_last_commit_in_list?(project) +- access = max_project_member_access(project) - css_class = "gl-sm-display-flex gl-align-items-center gl-vertical-align-middle!" if project.description.blank? && !show_last_commit_as_description - updated_tooltip = time_ago_with_tooltip(project.last_activity_date) - show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project) - last_pipeline = last_pipeline_from_status_cache(project) if show_pipeline_status_icon - css_controls_class = "with-pipeline-status" if show_pipeline_status_icon && last_pipeline.present? -- css_metadata_classes = "gl-display-flex gl-align-items-center gl-ml-5 gl-reset-color! icon-wrapper has-tooltip" +- css_metadata_classes = "gl-display-flex gl-align-items-center gl-reset-color! icon-wrapper has-tooltip" %li.project-row - if avatar .project-cell.gl-w-11 - = link_to project_path(project), class: dom_class(project) do - - if project.creator && use_creator_avatar - = render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '', class: 'gl-mr-5') - - else - = render Pajamas::AvatarComponent.new(project, size: 48, alt: '', class: 'gl-mr-5') + .project-avatar-container.gl-mr-5.gl-relative.gl-pb-4 + = link_to project_path(project), class: dom_class(project) do + - if project.creator && use_creator_avatar + = render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '') + - else + = render Pajamas::AvatarComponent.new(project, size: 48, alt: '') + + = visibility_level_content(project, css_class: 'project-visibility gl-absolute gl-display-flex gl-justify-content-center gl-align-items-center gl-bottom-0 gl-left-50p gl-w-6 gl-h-6 gl-bg-gray-50 gl-border gl-rounded-full gl-border-white gl-translate-x-n50') .project-cell{ class: css_class } .project-details.gl-pr-9.gl-sm-pr-0.gl-w-full.gl-display-flex.gl-flex-direction-column{ data: { testid: 'project-content', qa_project_name: project.name } } .gl-display-flex.gl-align-items-center.gl-flex-wrap @@ -35,8 +39,6 @@ %span.project-name< = project.name - = visibility_level_content(project, css_class: 'gl-mr-2') - - if project.catalog_resource = render partial: 'shared/ci_catalog_badge', locals: { href: explore_catalog_path(project.catalog_resource), css_class: 'gl-mr-2' } @@ -83,32 +85,31 @@ = _('Updated') = updated_tooltip - .project-cell{ class: "#{css_class} gl-display-none! gl-sm-display-table-cell!" } - .project-controls.gl-display-flex.gl-flex-direction-column.gl-align-items-flex-end.gl-w-full{ data: { testid: 'project_controls'} } - .controls.gl-display-flex.gl-align-items-center.gl-mb-2{ class: "#{css_controls_class} gl-pr-0!" } - - if show_pipeline_status_icon && last_pipeline.present? - - pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref) - %span.icon-wrapper.pipeline-status - = render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path + .project-cell.project-controls{ class: "#{css_class} gl-display-none! gl-sm-display-table-cell!", data: { testid: 'project_controls'} } + .controls.gl-display-flex.gl-align-items-center.gl-mb-2.gl-gap-4{ class: "#{css_controls_class} gl-pr-0! gl-justify-content-end!" } + - if show_pipeline_status_icon && last_pipeline.present? + - pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref) + %span.icon-wrapper.pipeline-status + = render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path - = render_if_exists 'shared/projects/archived', project: project - - if stars - = link_to project_starrers_path(project), class: "#{css_metadata_classes} stars", title: _('Stars'), data: { container: 'body', placement: 'top' } do - = sprite_icon('star-o', size: 14, css_class: 'gl-mr-2') - = badge_count(project.star_count) - - if show_count?(disabled: !forks, compact_mode: compact_mode) - = link_to project_forks_path(project), class: "#{css_metadata_classes} forks", title: _('Forks'), data: { container: 'body', placement: 'top' } do - = sprite_icon('fork', size: 14, css_class: 'gl-mr-2') - = badge_count(project.forks_count) - - if show_count?(disabled: !merge_requests, compact_mode: compact_mode) - = link_to project_merge_requests_path(project), class: "#{css_metadata_classes} merge-requests", title: _('Merge requests'), data: { container: 'body', placement: 'top' } do - = sprite_icon('git-merge', size: 14, css_class: 'gl-mr-2') - = badge_count(project.open_merge_requests_count) - - if show_count?(disabled: !issues, compact_mode: compact_mode) - = link_to project_issues_path(project), class: "#{css_metadata_classes} issues", title: _('Issues'), data: { container: 'body', placement: 'top' } do - = sprite_icon('issues', size: 14, css_class: 'gl-mr-2') - = badge_count(project.open_issues_count) - .updated-note.gl-font-sm.gl-white-space-nowrap.gl-justify-content-end - %span - = _('Updated') - = updated_tooltip + = render_if_exists 'shared/projects/archived', project: project + - if stars + = link_to project_starrers_path(project), class: "#{css_metadata_classes} stars", title: _('Stars'), data: { container: 'body', placement: 'top' } do + = sprite_icon('star-o', size: 14, css_class: 'gl-mr-2') + = badge_count(project.star_count) + - if show_count?(disabled: !forks, compact_mode: compact_mode) + = link_to project_forks_path(project), class: "#{css_metadata_classes} forks", title: _('Forks'), data: { container: 'body', placement: 'top' } do + = sprite_icon('fork', size: 14, css_class: 'gl-mr-2') + = badge_count(project.forks_count) + - if show_count?(disabled: !merge_requests, compact_mode: compact_mode) + = link_to project_merge_requests_path(project), class: "#{css_metadata_classes} merge-requests", title: _('Merge requests'), data: { container: 'body', placement: 'top' } do + = sprite_icon('git-merge', size: 14, css_class: 'gl-mr-2') + = badge_count(project.open_merge_requests_count) + - if show_count?(disabled: !issues, compact_mode: compact_mode) + = link_to project_issues_path(project), class: "#{css_metadata_classes} issues", title: _('Issues'), data: { container: 'body', placement: 'top' } do + = sprite_icon('issues', size: 14, css_class: 'gl-mr-2') + = badge_count(project.open_issues_count) + .updated-note.gl-font-sm.gl-white-space-nowrap.gl-justify-content-end + %span + = _('Updated') + = updated_tooltip diff --git a/app/views/shared/projects/_project_card.html.haml b/app/views/shared/projects/_project_card.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..7de1fac4b3a641d5f4c87ce9f4f590288874b0f5 --- /dev/null +++ b/app/views/shared/projects/_project_card.html.haml @@ -0,0 +1,90 @@ +- avatar = local_assigns[:avatar] != false +- stars = local_assigns[:stars] != false +- forks = local_assigns[:forks] != false +- merge_requests = local_assigns[:merge_requests] != false +- issues = local_assigns[:issues] != false +- pipeline_status = local_assigns[:pipeline_status] != false +- skip_namespace = local_assigns[:skip_namespace] == true +- compact_mode = local_assigns[:compact_mode] == true +- use_creator_avatar = local_assigns[:use_creator_avatar] == true +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && can_show_last_commit_in_list?(project) +- updated_tooltip = time_ago_with_tooltip(project.last_activity_date) +- show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project) +- last_pipeline = last_pipeline_from_status_cache(project) if show_pipeline_status_icon +- css_controls_class = "with-pipeline-status" if show_pipeline_status_icon && last_pipeline.present? +- css_metadata_classes = "gl-display-flex gl-align-items-center gl-ml-0! gl-reset-color! icon-wrapper has-tooltip" + += render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card gl-justify-content-space-between gl-lg-w-25p gl-flex-grow-1 gl-shrink-0 gl-mt-0' }, header_options: { class: 'gl-new-card-header gl-flex-grow-1 gl-align-items-flex-start gl-border-b-0 gl-px-4 gl-gap-5' }, body_options: { class: 'gl-new-card-body gl-px-4 gl-py-4' }) do |c| + - c.with_header do + - if avatar + .project-avatar-container.gl-relative.gl-pb-4 + = link_to project_path(project), class: dom_class(project) do + - if project.creator && use_creator_avatar + = render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '') + - else + = render Pajamas::AvatarComponent.new(project, size: 48, alt: '') + + = visibility_level_content(project, css_class: 'project-visibility gl-absolute gl-display-flex gl-justify-content-center gl-align-items-center gl-bottom-0 gl-left-50p gl-w-6 gl-h-6 gl-bg-gray-50 gl-border gl-rounded-full gl-border-white gl-translate-x-n50') + + .gl-w-full.gl-pt-2.gl-word-break-word + %h2.gl-font-base.gl-line-height-20.gl-my-0.gl-flex-basis-full + = link_to project_path(project), class: 'text-plain gl-mr-3 js-prefetch-document', title: project.name do + %span.namespace-name.gl-font-weight-normal + - if project.namespace && !skip_namespace + = project.namespace.human_name + \/ + %span.project-name< + = project.name + + - if show_last_commit_as_description + .description.gl-display-none.gl-sm-display-block.gl-mt-2.gl-font-sm + = link_to_markdown(project.commit.title, project_commit_path(project, project.commit), class: "commit-row-message") + - elsif project.description.present? + .description.gl-display-none.gl-sm-display-block.gl-mt-2.gl-font-sm + = markdown_field(project, :description) + + - if project.topics.any? + .gl-mt-3.gl-ml-n1 + = render "shared/projects/topics", project: project.present(current_user: current_user) + - if project.catalog_resource + = render partial: 'shared/ci_catalog_badge', locals: { href: project_ci_catalog_resource_path(project, project.catalog_resource) } + + - if explore_projects_tab? && project_license_name(project) + %span.gl-display-inline-flex.gl-align-items-center.gl-mr-3 + = sprite_icon('scale', size: 14, css_class: 'gl-mr-2') + = project_license_name(project) + + - if !explore_projects_tab? + = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: project, additional_classes: 'gl-ml-3!' + - c.with_body do + .project-controls{ data: { testid: 'project_controls'} } + .gl-display-flex.gl-align-items-center.gl-gap-2.gl-mb-2.gl-justify-content-space-between.gl-flex-wrap + .controls.gl-display-flex.gl-align-items-center.gl-gap-4{ class: "#{css_controls_class} gl-pr-0!" } + - if stars + = link_to project_starrers_path(project), class: "#{css_metadata_classes} stars", title: _('Stars'), data: { container: 'body', placement: 'top' } do + = sprite_icon('star-o', size: 14, css_class: 'gl-mr-2') + = badge_count(project.star_count) + - if show_count?(disabled: !forks, compact_mode: compact_mode) + = link_to project_forks_path(project), class: "#{css_metadata_classes} forks", title: _('Forks'), data: { container: 'body', placement: 'top' } do + = sprite_icon('fork', size: 14, css_class: 'gl-mr-2') + = badge_count(project.forks_count) + - if show_count?(disabled: !merge_requests, compact_mode: compact_mode) + = link_to project_merge_requests_path(project), class: "#{css_metadata_classes} merge-requests", title: _('Merge requests'), data: { container: 'body', placement: 'top' } do + = sprite_icon('git-merge', size: 14, css_class: 'gl-mr-2') + = badge_count(project.open_merge_requests_count) + - if show_count?(disabled: !issues, compact_mode: compact_mode) + = link_to project_issues_path(project), class: "#{css_metadata_classes} issues", title: _('Issues'), data: { container: 'body', placement: 'top' } do + = sprite_icon('issues', size: 14, css_class: 'gl-mr-2') + = badge_count(project.open_issues_count) + + .gl-display-flex.gl-align-items-center.gl-gap-2.gl-mr-n2 + - if show_pipeline_status_icon && last_pipeline.present? + - pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref) + %span.icon-wrapper.pipeline-status + = render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path + + = render_if_exists 'shared/projects/archived', project: project + .updated-note.gl-font-sm.gl-white-space-nowrap.gl-justify-content-start + %span + = _('Updated') + = updated_tooltip diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index a39d5b6245b2a956031c26416e90b2b67da333cf..e6fd5618582c7145f80a07c221b6f1ae0319c61d 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -142,7 +142,7 @@ = s_('UserProfile|Personal projects') - if profile_tab?(:starred) %li.js-starred-tab - = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do + = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json), card_mode: true } do = s_('UserProfile|Starred projects') - if profile_tab?(:snippets) %li.js-snippets-tab diff --git a/ee/app/views/shared/projects/_archived.html.haml b/ee/app/views/shared/projects/_archived.html.haml index c6598b356f16c55b75cd17e563c25c723f357fa0..2adc29a8b1b0848aa4022c2f8f1c98d2a3316807 100644 --- a/ee/app/views/shared/projects/_archived.html.haml +++ b/ee/app/views/shared/projects/_archived.html.haml @@ -1,4 +1,4 @@ - if project.marked_for_deletion? - = gl_badge_tag _('pending deletion'), { variant: :warning }, { class: 'gl-display-flex gl-ml-3' } + = gl_badge_tag _('pending deletion'), { variant: :warning } - elsif project.archived - = gl_badge_tag _('archived'), { variant: :warning }, { class: 'gl-display-flex gl-ml-3' } + = gl_badge_tag _('archived'), { variant: :warning } diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb index f776b16713d109c336e59dfebb4b53971f5c7e71..727b87c69dd8cea5ec35efe2093b0f82ea49053c 100644 --- a/spec/features/users/overview_spec.rb +++ b/spec/features/users/overview_spec.rb @@ -95,7 +95,7 @@ def push_code_contribution it 'shows one entry in the list of projects' do page.within('.projects-block') do - expect(page).to have_selector('.project-row', count: 1) + expect(page).to have_selector('.gl-card', count: 1) end end @@ -103,9 +103,9 @@ def push_code_contribution expect(find('#js-overview .projects-block')).to have_selector('.js-view-all', visible: true) end - it 'shows projects in "compact mode"' do + it 'shows projects in "card mode"' do page.within('#js-overview .projects-block') do - expect(find('.js-projects-list-holder')).to have_selector('.compact') + expect(find('.js-projects-list-holder')).to have_css('.gl-card') end end end @@ -119,9 +119,9 @@ def push_code_contribution include_context 'visit overview tab' - it 'shows max. ten entries in the list of projects' do + it 'shows max. 3 entries in the list of projects' do page.within('.projects-block') do - expect(page).to have_selector('.project-row', count: 10) + expect(page).to have_selector('.gl-card', count: 3) end end diff --git a/spec/views/shared/projects/_list.html.haml_spec.rb b/spec/views/shared/projects/_list.html.haml_spec.rb index 1b6c4e00c97f51f348439a24ef403ed834ecd72e..ff295662e3c6e22731ae8f297aa08351901ef252 100644 --- a/spec/views/shared/projects/_list.html.haml_spec.rb +++ b/spec/views/shared/projects/_list.html.haml_spec.rb @@ -31,6 +31,20 @@ expect(rendered).not_to have_css('a.issues') expect(rendered).not_to have_css('a.merge-requests') end + + it 'renders list in list view' do + expect(rendered).not_to have_css('.gl-new-card') + end + end + + context 'with projects in card mode' do + let(:projects) { build_stubbed_list(:project, 1) } + + it 'renders card mode when set to true' do + render template: 'shared/projects/_list', locals: { card_mode: true } + + expect(rendered).to have_css('.gl-new-card') + end end context 'without projects' do diff --git a/spec/views/shared/projects/_project_card.html.haml_spec.rb b/spec/views/shared/projects/_project_card.html.haml_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..4f4e31176af0a522de4490fbc5c3ea0455d13d06 --- /dev/null +++ b/spec/views/shared/projects/_project_card.html.haml_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'shared/projects/_project_card.html.haml', feature_category: :shared do + let(:project) { build(:project) } + + before do + allow(view) + .to receive(:current_application_settings) + .and_return(Gitlab::CurrentSettings.current_application_settings) + allow(view).to receive(:can?).and_return(true) + end + + it 'renders as a card component' do + render 'shared/projects/project_card', use_creator_avatar: true, project: project + + expect(rendered).to have_selector('.gl-new-card') + end + + it 'renders creator avatar if project has a creator' do + render 'shared/projects/project_card', use_creator_avatar: true, project: project + + expect(rendered).to have_selector('img.gl-avatar') + end + + it 'renders a generic avatar if project does not have a creator' do + project.creator = nil + + render 'shared/projects/project_card', use_creator_avatar: true, project: project + + expect(rendered).to have_selector('.gl-avatar-identicon') + end +end