From 2ad0b279bbe9503b393517c99efaedc3253eb4da Mon Sep 17 00:00:00 2001 From: Shane Maglangit Date: Wed, 17 Dec 2025 20:21:13 +0800 Subject: [PATCH] Scaffold the Explore > Projects Vue app --- .gitlab/CODEOWNERS | 3 -- .../explore/projects/components/app.vue | 9 ++++ .../javascripts/explore/projects/index.js | 16 ++++++ .../pages/explore/projects/index.js | 2 + .../explore/projects_controller.rb | 8 +-- app/views/explore/projects/index.html.haml | 7 ++- app/views/explore/projects/starred.html.haml | 3 -- app/views/explore/projects/trending.html.haml | 3 -- .../wip/explore_projects_vue.yml | 10 ++++ config/lint/deprecations.yml | 6 --- config/routes/explore.rb | 4 ++ .../explore/projects_controller_spec.rb | 10 ++-- spec/features/dashboard/root_explore_spec.rb | 5 ++ spec/features/dashboard/shortcuts_spec.rb | 3 ++ .../explore/user_explores_projects_spec.rb | 9 +++- .../projects/user_sorts_projects_spec.rb | 6 +++ .../explore/projects/components/app_spec.js | 16 ++++++ .../explore/projects/index.html.haml_spec.rb | 54 +++++++++++++++++++ 18 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 app/assets/javascripts/explore/projects/components/app.vue create mode 100644 app/assets/javascripts/explore/projects/index.js delete mode 100644 app/views/explore/projects/starred.html.haml delete mode 100644 app/views/explore/projects/trending.html.haml create mode 100644 config/feature_flags/wip/explore_projects_vue.yml create mode 100644 spec/frontend/explore/projects/components/app_spec.js create mode 100644 spec/views/explore/projects/index.html.haml_spec.rb diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index a1148250d58326..166c3581dd9680 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -1828,9 +1828,6 @@ lib/api/entities/project_identity.rb lib/api/entities/project.rb ee/lib/ee/api/entities/project.rb -[Category:Groups & Projects] @gitlab-com/gl-infra/tenant-scale/organizations/groups-and-projects -app/views/explore/projects/trending.html.haml - [Compliance] @gitlab-org/software-supply-chain-security/compliance/engineering /app/services/audit_events/build_service.rb /ee/app/services/ee/audit_events/build_service.rb diff --git a/app/assets/javascripts/explore/projects/components/app.vue b/app/assets/javascripts/explore/projects/components/app.vue new file mode 100644 index 00000000000000..cd07c5e5ddd187 --- /dev/null +++ b/app/assets/javascripts/explore/projects/components/app.vue @@ -0,0 +1,9 @@ + + + diff --git a/app/assets/javascripts/explore/projects/index.js b/app/assets/javascripts/explore/projects/index.js new file mode 100644 index 00000000000000..71347d19d38745 --- /dev/null +++ b/app/assets/javascripts/explore/projects/index.js @@ -0,0 +1,16 @@ +import Vue from 'vue'; +import ExploreProjectsApp from '~/explore/projects/components/app.vue'; + +export const initExploreProjects = () => { + const el = document.getElementById('js-explore-projects'); + + if (!el) return null; + + return new Vue({ + el, + name: 'ExploreProjectsRoot', + render(createElement) { + return createElement(ExploreProjectsApp, {}); + }, + }); +}; diff --git a/app/assets/javascripts/pages/explore/projects/index.js b/app/assets/javascripts/pages/explore/projects/index.js index 84a54e1ef3784a..177b96cece3015 100644 --- a/app/assets/javascripts/pages/explore/projects/index.js +++ b/app/assets/javascripts/pages/explore/projects/index.js @@ -1,5 +1,7 @@ import { initProjectsFilteredSearchAndSort } from '~/projects/filtered_search_and_sort'; +import { initExploreProjects } from '~/explore/projects'; +initExploreProjects(); initProjectsFilteredSearchAndSort({ sortEventName: 'use_sort_projects_explore', filterEventName: 'use_filter_bar_projects_explore', diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index 761b6492d7c821..d6a952d5d24130 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -46,8 +46,8 @@ def index def trending if Feature.enabled?(:retire_trending_projects, current_user) respond_to do |format| - format.html { redirect_to explore_root_path } - format.json { redirect_to explore_root_path(format: :json), status: :found } + format.html { redirect_to starred_explore_projects_path } + format.json { redirect_to starred_explore_projects_path(format: :json), status: :found } end return end @@ -56,7 +56,7 @@ def trending @projects = load_projects respond_to do |format| - format.html + format.html { render :index } format.json do render json: { html: view_to_html_string("explore/projects/_projects", projects: @projects) @@ -70,7 +70,7 @@ def starred @projects = load_projects.reorder('star_count DESC') respond_to do |format| - format.html + format.html { render :index } format.json do render json: { html: view_to_html_string("explore/projects/_projects", projects: @projects) diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml index 50d79eeefdb14e..d8f3596cf6203d 100644 --- a/app/views/explore/projects/index.html.haml +++ b/app/views/explore/projects/index.html.haml @@ -1,5 +1,8 @@ - page_canonical_link explore_projects_url = render 'explore/projects/head' -= render 'explore/projects/nav' -= render 'projects', projects: @projects +- if Feature.enabled?(:explore_projects_vue, current_user) + #js-explore-projects +- else + = render 'explore/projects/nav' + = render 'projects', projects: @projects diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml deleted file mode 100644 index 8840a2dc0e3bd6..00000000000000 --- a/app/views/explore/projects/starred.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -= render 'explore/projects/head' -= render 'explore/projects/nav' -= render 'projects', projects: @projects diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml deleted file mode 100644 index 8840a2dc0e3bd6..00000000000000 --- a/app/views/explore/projects/trending.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -= render 'explore/projects/head' -= render 'explore/projects/nav' -= render 'projects', projects: @projects diff --git a/config/feature_flags/wip/explore_projects_vue.yml b/config/feature_flags/wip/explore_projects_vue.yml new file mode 100644 index 00000000000000..f3192b28612196 --- /dev/null +++ b/config/feature_flags/wip/explore_projects_vue.yml @@ -0,0 +1,10 @@ +--- +name: explore_projects_vue +description: Migrate Explore > Projects to Vue +feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/13786 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/216796 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/584084 +milestone: '18.7' +group: group::organizations +type: wip +default_enabled: false diff --git a/config/lint/deprecations.yml b/config/lint/deprecations.yml index 305e82351de77d..37bc6fbc89edc7 100644 --- a/config/lint/deprecations.yml +++ b/config/lint/deprecations.yml @@ -1,7 +1 @@ files: - - reason: "Trending projects is scheduled for removal on the 19.0 release" - feature_issue: https://gitlab.com/groups/gitlab-org/-/work_items/18493 - removal_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/583184 - feature_category: groups_and_projects - paths: - - app/views/explore/projects/trending.html.haml diff --git a/config/routes/explore.rb b/config/routes/explore.rb index 7716015babaab8..269adaafac93e0 100644 --- a/config/routes/explore.rb +++ b/config/routes/explore.rb @@ -3,6 +3,10 @@ namespace :explore do resources :projects, only: [:index] do collection do + get :index + get :active, to: 'projects#index', as: :active + get :inactive, to: 'projects#index', as: :inactive + get :all, to: 'projects#index', as: :all get :trending get :starred get :topics diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index 6f1f28054a7be8..e746acb2b4b052 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -24,10 +24,10 @@ describe 'GET #trending.json' do render_views - it 'redirects to explore root path with json format', :aggregate_failures do + it 'redirects to most starred projects with json format', :aggregate_failures do get :trending, format: :json - expect(response).to redirect_to(explore_root_path(format: :json)) + expect(response).to redirect_to(starred_explore_projects_path(format: :json)) expect(response).to have_gitlab_http_status(:found) end @@ -62,10 +62,10 @@ end describe 'GET #trending' do - it 'redirects to explore root path' do + it 'redirects to most starred projects' do get :trending - expect(response).to redirect_to(explore_root_path) + expect(response).to redirect_to(starred_explore_projects_path) end context 'when `retire_trending_projects` flag is disabled' do @@ -272,7 +272,7 @@ end it { is_expected.to respond_with(:success) } - it { is_expected.to render_template("explore/projects/#{endpoint}") } + it { is_expected.to render_template('explore/projects/index') } end describe "GET #{endpoint}.json" do diff --git a/spec/features/dashboard/root_explore_spec.rb b/spec/features/dashboard/root_explore_spec.rb index 6d457200efb1c0..40e06ba0d96d96 100644 --- a/spec/features/dashboard/root_explore_spec.rb +++ b/spec/features/dashboard/root_explore_spec.rb @@ -8,6 +8,11 @@ let_it_be(:internal_project) { create(:project, :internal) } let_it_be(:private_project) { create(:project, :private) } + before do + # Feature test will be added separately in https://gitlab.com/gitlab-org/gitlab/-/issues/520596 + stub_feature_flags(explore_projects_vue: false) + end + context 'when logged in' do let_it_be(:user) { create(:user) } diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index a9fc319c1234ec..5fd22e58d007bf 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -61,6 +61,9 @@ context 'logged out', :with_current_organization do before do visit explore_root_path + + # Feature test will be added separately in https://gitlab.com/gitlab-org/gitlab/-/issues/520596 + stub_feature_flags(explore_projects_vue: false) end it 'navigates to pages' do diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb index 2f0bd210cac4ab..f0327737268c51 100644 --- a/spec/features/explore/user_explores_projects_spec.rb +++ b/spec/features/explore/user_explores_projects_spec.rb @@ -3,6 +3,11 @@ require 'spec_helper' RSpec.describe 'User explores projects', feature_category: :user_profile do + before do + # Feature test will be added separately in https://gitlab.com/gitlab-org/gitlab/-/issues/520596 + stub_feature_flags(explore_projects_vue: false) + end + shared_examples 'an "Explore > Projects" page with sidebar and breadcrumbs' do |page_path, params| before do visit send(page_path, params) @@ -125,9 +130,9 @@ TrendingProject.refresh! end - it 'redirects to root explore page' do + it 'redirects to most starred projects page' do visit trending_explore_projects_path - expect(page).to have_current_path(explore_root_path) + expect(page).to have_current_path(starred_explore_projects_path) end context 'when `retire_trending_projects` flag is disabled' do diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb index a4e85e4c4f7c13..f1b8c98cd85d8f 100644 --- a/spec/features/projects/user_sorts_projects_spec.rb +++ b/spec/features/projects/user_sorts_projects_spec.rb @@ -24,6 +24,9 @@ def find_dropdown_toggle end it "is set on the explore_projects_path" do + # Feature test will be added separately in https://gitlab.com/gitlab-org/gitlab/-/issues/520596 + stub_feature_flags(explore_projects_vue: false) + visit(explore_projects_path) within '[data-testid=groups-projects-sort]' do @@ -50,6 +53,9 @@ def find_dropdown_toggle context "from explore projects", :js do before do + # Feature test will be added separately in https://gitlab.com/gitlab-org/gitlab/-/issues/520596 + stub_feature_flags(explore_projects_vue: false) + sign_in(user) visit(explore_projects_path) within '[data-testid=groups-projects-sort]' do diff --git a/spec/frontend/explore/projects/components/app_spec.js b/spec/frontend/explore/projects/components/app_spec.js new file mode 100644 index 00000000000000..4afb1220a07476 --- /dev/null +++ b/spec/frontend/explore/projects/components/app_spec.js @@ -0,0 +1,16 @@ +import { shallowMount } from '@vue/test-utils'; +import ExploreProjectsApp from '~/explore/projects/components/app.vue'; + +describe('ExploreProjectsApp', () => { + let wrapper; + + const createComponent = ({ mountFn = shallowMount } = {}) => { + wrapper = mountFn(ExploreProjectsApp); + }; + + it('renders', () => { + createComponent(); + + expect(wrapper.find('div').exists()).toBe(true); + }); +}); diff --git a/spec/views/explore/projects/index.html.haml_spec.rb b/spec/views/explore/projects/index.html.haml_spec.rb new file mode 100644 index 00000000000000..81d2f0a00b29e3 --- /dev/null +++ b/spec/views/explore/projects/index.html.haml_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'explore/projects/index.html.haml', feature_category: :groups_and_projects do + let_it_be(:user) { build_stubbed(:user) } + + before do + allow(view).to receive_messages(current_user: user, explore_projects_app_data: {}) + end + + it 'renders the head partial' do + render + + expect(rendered).to render_template('explore/projects/_head') + end + + context 'when explore_projects_vue feature flag is enabled' do + it 'does not render the Vue app' do + render + + expect(rendered).to have_selector('#js-explore-projects') + end + + it 'does not render the legacy partials' do + render + + expect(rendered).not_to render_template('explore/projects/_nav') + expect(rendered).not_to render_template('explore/projects/_projects') + end + end + + context 'when explore_projects_vue feature flag is disabled' do + let_it_be(:projects) { [build_stubbed(:project, :public)] } + + before do + stub_feature_flags(explore_projects_vue: false) + assign(:projects, projects) + end + + it 'does not render the Vue app' do + render + + expect(rendered).not_to have_selector('#js-explore-projects') + end + + it 'renders the legacy partials' do + render + + expect(rendered).to render_template('explore/projects/_nav') + expect(rendered).to render_template('explore/projects/_projects') + end + end +end -- GitLab