diff --git a/app/assets/javascripts/pages/projects/commits/show/index.js b/app/assets/javascripts/pages/projects/commits/show/index.js
index 5d6bccc88ae9670fd6b843c2479eec46487f878f..011759a5f1cd6f67435ad5ccf75066c2e1552d37 100644
--- a/app/assets/javascripts/pages/projects/commits/show/index.js
+++ b/app/assets/javascripts/pages/projects/commits/show/index.js
@@ -4,8 +4,14 @@ import CommitsList from '~/commits';
import GpgBadges from '~/gpg_badges';
import { mountCommits, initCommitsRefSwitcher } from '~/projects/commits';
import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal';
+import initCommitListApp from '~/projects/commits/init_commit_list_app';
+
+if (document.querySelector('.js-project-commits-show')) {
+ new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new
+} else {
+ initCommitListApp();
+}
-new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new
addShortcutsExtension(ShortcutsNavigation);
GpgBadges.fetch();
mountCommits(document.getElementById('js-author-dropdown'));
diff --git a/app/assets/javascripts/projects/commits/components/commit_list_app.vue b/app/assets/javascripts/projects/commits/components/commit_list_app.vue
new file mode 100644
index 0000000000000000000000000000000000000000..80f79814b5dc0e723ab88d51d47e57de99a2904f
--- /dev/null
+++ b/app/assets/javascripts/projects/commits/components/commit_list_app.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/app/assets/javascripts/projects/commits/components/commit_list_header.vue b/app/assets/javascripts/projects/commits/components/commit_list_header.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ff8e38a31699349e4a359d2f9e1dc7c0a5923732
--- /dev/null
+++ b/app/assets/javascripts/projects/commits/components/commit_list_header.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
{{ projectPath }}
+
+
diff --git a/app/assets/javascripts/projects/commits/components/commit_list_item.vue b/app/assets/javascripts/projects/commits/components/commit_list_item.vue
new file mode 100644
index 0000000000000000000000000000000000000000..33a634d0040b336b8c095745ecf443b4ab9b87e7
--- /dev/null
+++ b/app/assets/javascripts/projects/commits/components/commit_list_item.vue
@@ -0,0 +1,17 @@
+
+
+
+
+ {{ commit.message }}
+
+
diff --git a/app/assets/javascripts/projects/commits/init_commit_list_app.js b/app/assets/javascripts/projects/commits/init_commit_list_app.js
new file mode 100644
index 0000000000000000000000000000000000000000..ff69f19d87fc2a187d41fccbc1f848f9797e9ddf
--- /dev/null
+++ b/app/assets/javascripts/projects/commits/init_commit_list_app.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import CommitListApp from './components/commit_list_app.vue';
+
+export default function initCommitListApp() {
+ const commitListEl = document.getElementById('js-commit-list');
+
+ if (!commitListEl) return;
+
+ const { projectPath, currentPath } = commitListEl.dataset;
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: commitListEl,
+ provide: {
+ projectPath,
+ currentPath,
+ },
+ render(h) {
+ return h(CommitListApp, {});
+ },
+ });
+}
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index a481e4ad3f579e4c18a5ddbb8ce7b0fb3ec0634e..261bca63c81798cc5eb5e7ad27ec36ef25e7b11f 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -9,39 +9,43 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_commits_path(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
-.js-project-commits-show{ 'data-commits-limit' => @limit }
- .tree-holder.gl-mt-5
- .nav-block
- .tree-ref-container
- .tree-ref-holder.gl-max-w-26
- #js-project-commits-ref-switcher{ data: { "project-id" => @project.id, "ref" => @ref, "commits_path": project_commits_path(@project), "ref_type": @ref_type.to_s, "tree_path": @path } }
-
- %ul.breadcrumb.repo-breadcrumb
- = commits_breadcrumbs
- #js-author-dropdown{ data: { 'commits_path': project_commits_path(@project), 'project_id': @project.id } }
- .tree-controls
- .control
- = link_button_to _('Browse files'), path_to_browse_file_or_directory(@project, @ref, @path)
- - if @merge_request.present?
+- if Feature.enabled?(:project_commits_refactor, @project)
+ #js-commit-list{ data: { "project-path" => @project.path } }
+
+- else
+ .js-project-commits-show{ 'data-commits-limit' => @limit }
+ .tree-holder.gl-mt-5
+ .nav-block
+ .tree-ref-container
+ .tree-ref-holder.gl-max-w-26
+ #js-project-commits-ref-switcher{ data: { "project-id" => @project.id, "ref" => @ref, "commits_path": project_commits_path(@project), "ref_type": @ref_type.to_s, "tree_path": @path } }
+
+ %ul.breadcrumb.repo-breadcrumb
+ = commits_breadcrumbs
+ #js-author-dropdown{ data: { 'commits_path': project_commits_path(@project), 'project_id': @project.id } }
+ .tree-controls
+ .control
+ = link_button_to _('Browse files'), path_to_browse_file_or_directory(@project, @ref, @path)
+ - if @merge_request.present?
+ .control.gl-hidden.md:gl-block
+ = link_button_to _("View open merge request"), project_merge_request_path(@project, @merge_request)
+ - elsif create_mr_button?(from: @ref, source_project: @project)
+ .control.gl-hidden.md:gl-block
+ = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do
+ = _("Create merge request")
+
+ .control
+ = form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do
+ = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 sm:gl-mt-0 gl-min-w-full', spellcheck: false }
.control.gl-hidden.md:gl-block
- = link_button_to _("View open merge request"), project_merge_request_path(@project, @merge_request)
- - elsif create_mr_button?(from: @ref, source_project: @project)
- .control.gl-hidden.md:gl-block
- = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do
- = _("Create merge request")
-
- .control
- = form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do
- = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 sm:gl-mt-0 gl-min-w-full', spellcheck: false }
- .control.gl-hidden.md:gl-block
- = link_button_to nil, project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), icon: 'rss'
+ = link_button_to nil, project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), icon: 'rss'
- = render_if_exists 'projects/commits/mirror_status'
+ = render_if_exists 'projects/commits/mirror_status'
- %div{ id: dom_id(@project) }
- %ol#commits-list.list-unstyled.content_list
- = render 'commits', project: @project, ref: @ref, is_commits_page: true
- = gl_loading_icon(size: 'lg', css_class: 'loading hide')
+ %div{ id: dom_id(@project) }
+ %ol#commits-list.list-unstyled.content_list
+ = render 'commits', project: @project, ref: @ref, is_commits_page: true
+ = gl_loading_icon(size: 'lg', css_class: 'loading hide')
-# https://gitlab.com/gitlab-org/gitlab/-/issues/408388#note_1578533983
#js-ambiguous-ref-modal{ data: { ambiguous: @is_ambiguous_ref.to_s, ref: current_ref } }
diff --git a/config/feature_flags/wip/project_commits_refactor.yml b/config/feature_flags/wip/project_commits_refactor.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a116ea0259a98b11fb1ea961c9821837cc30fdb4
--- /dev/null
+++ b/config/feature_flags/wip/project_commits_refactor.yml
@@ -0,0 +1,9 @@
+---
+name: project_commits_refactor
+feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/17482
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/192147
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/545170
+milestone: '18.1'
+group: group::source code
+type: wip
+default_enabled: false
diff --git a/spec/frontend/projects/commits/components/commit_list_app_spec.js b/spec/frontend/projects/commits/components/commit_list_app_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..ccca13512a043030d490d6b9da0928cf27a78914
--- /dev/null
+++ b/spec/frontend/projects/commits/components/commit_list_app_spec.js
@@ -0,0 +1,26 @@
+import { shallowMount } from '@vue/test-utils';
+import CommitListApp from '~/projects/commits/components/commit_list_app.vue';
+import CommitListHeader from '~/projects/commits/components/commit_list_header.vue';
+
+describe('Commit List App', () => {
+ let wrapper;
+ const createComponent = (provide = {}) => {
+ wrapper = shallowMount(CommitListApp, {
+ provide: {
+ ...provide,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ const findCommitHeader = () => wrapper.findComponent(CommitListHeader);
+
+ describe('commit header', () => {
+ it('renders the commit header component', () => {
+ expect(findCommitHeader().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 1ae63a7abd37236aa7ad24aebb6bdf777d771e19..073b86f878724b5661ade99db46c3bc5b694e549 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -341,6 +341,10 @@
# Please see https://gitlab.com/groups/gitlab-org/-/epics/17781 for tracking the progress.
stub_feature_flags(repository_file_tree_browser: false)
+ # Since we are very early in development of this feature, it might cause unexpected behaviors when the flag is enabled
+ # Please see https://gitlab.com/groups/gitlab-org/-/epics/17482 for tracking the progress.
+ stub_feature_flags(project_commits_refactor: false)
+
# New issue page can cause tests to fail if they link to issue or issue list page
# Default false while we make it compatible
stub_feature_flags(work_item_view_for_issues: false)
@@ -351,6 +355,7 @@
# New personal homepage is still a WIP and not functional.
stub_feature_flags(personal_homepage: false)
+
else
unstub_all_feature_flags
end