From db368a66e75d300453c45073e219a396ffdddeb9 Mon Sep 17 00:00:00 2001
From: Marco Zille <marco.zille@gmail.com>
Date: Tue, 13 Aug 2024 16:36:22 +0200
Subject: [PATCH] Added todos_vue_application feature flag

Instead of interweaving the old todos app on `/dashboard/todos` with the
new Vue app, we create a new route `/dashboard/todos/vue` which is a
little more green field.

This will allow us to work without the CSS and JS tech-debt of the old
page. Once the implementation of `/dashboard/todos/vue` is a little more
progressed we can feature flag it on the route level. But in the mean
time it's also nice that people which have the FF enabled, can just
navigate to the old route as well.

Follow-up steps would be switching out the route based on the FF in the
nav as well.

Changelog: added
---
 .../pages/dashboard/todos/vue/index.js        |  3 ++
 .../todos/components/todos_app.vue            |  5 ++++
 app/assets/javascripts/todos/index.js         | 17 +++++++++++
 app/controllers/dashboard/todos_controller.rb |  4 +++
 .../todos/_user_has_no_todos.html.haml        |  8 ++++++
 app/views/dashboard/todos/index.html.haml     |  9 +-----
 app/views/dashboard/todos/vue.html.haml       | 17 +++++++++++
 .../wip/todos_vue_application.yml             |  9 ++++++
 config/routes/dashboard.rb                    |  1 +
 .../dashboard/todos_controller_spec.rb        | 28 ++++++++++++++++++-
 10 files changed, 92 insertions(+), 9 deletions(-)
 create mode 100644 app/assets/javascripts/pages/dashboard/todos/vue/index.js
 create mode 100644 app/assets/javascripts/todos/components/todos_app.vue
 create mode 100644 app/assets/javascripts/todos/index.js
 create mode 100644 app/views/dashboard/todos/_user_has_no_todos.html.haml
 create mode 100644 app/views/dashboard/todos/vue.html.haml
 create mode 100644 config/feature_flags/wip/todos_vue_application.yml

diff --git a/app/assets/javascripts/pages/dashboard/todos/vue/index.js b/app/assets/javascripts/pages/dashboard/todos/vue/index.js
new file mode 100644
index 000000000000..3829b9845dff
--- /dev/null
+++ b/app/assets/javascripts/pages/dashboard/todos/vue/index.js
@@ -0,0 +1,3 @@
+import initTodosApp from '~/todos';
+
+initTodosApp();
diff --git a/app/assets/javascripts/todos/components/todos_app.vue b/app/assets/javascripts/todos/components/todos_app.vue
new file mode 100644
index 000000000000..282d3173b011
--- /dev/null
+++ b/app/assets/javascripts/todos/components/todos_app.vue
@@ -0,0 +1,5 @@
+<script>
+export default {};
+</script>
+
+<template><div></div></template>
diff --git a/app/assets/javascripts/todos/index.js b/app/assets/javascripts/todos/index.js
new file mode 100644
index 000000000000..6bd24f65d3fb
--- /dev/null
+++ b/app/assets/javascripts/todos/index.js
@@ -0,0 +1,17 @@
+import Vue from 'vue';
+import TodosApp from './components/todos_app.vue';
+
+export default () => {
+  const el = document.getElementById('js-todos-app-root');
+
+  if (!el) {
+    return false;
+  }
+
+  return new Vue({
+    el,
+    render(createElement) {
+      return createElement(TodosApp);
+    },
+  });
+};
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index b1a8ac351bf9..d06d053a3d11 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -22,6 +22,10 @@ def index
     @allowed_todos = ::Todos::AllowedTargetFilterService.new(@todos, current_user).execute
   end
 
+  def vue
+    redirect_to(dashboard_todos_path, status: :found) unless Feature.enabled?(:todos_vue_application, current_user)
+  end
+
   def destroy
     todo = current_user.todos.find(params[:id])
 
diff --git a/app/views/dashboard/todos/_user_has_no_todos.html.haml b/app/views/dashboard/todos/_user_has_no_todos.html.haml
new file mode 100644
index 000000000000..fa383ecba1f0
--- /dev/null
+++ b/app/views/dashboard/todos/_user_has_no_todos.html.haml
@@ -0,0 +1,8 @@
+= render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-todos-md.svg',
+      title: s_("Todos|Your To-Do List shows what to work on next")) do |c|
+
+  - c.with_description do
+    %p
+      = (s_("Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List.") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe
+    %p
+      = s_("Todos|It's how you always know what to work on next.")
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index ee92fd857749..4bc7e7c5f29e 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -114,11 +114,4 @@
             = link_to s_("Todos|Do you want to remove the filters?"), todos_filter_path(without: [:project_id, :author_id, :type, :action_id])
 
   - else
-    = render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-todos-md.svg',
-      title: s_("Todos|Your To-Do List shows what to work on next")) do |c|
-
-      - c.with_description do
-        %p
-          = (s_("Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List.") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe
-        %p
-          = s_("Todos|It's how you always know what to work on next.")
+    = render 'dashboard/todos/user_has_no_todos'
diff --git a/app/views/dashboard/todos/vue.html.haml b/app/views/dashboard/todos/vue.html.haml
new file mode 100644
index 000000000000..a4e741166931
--- /dev/null
+++ b/app/views/dashboard/todos/vue.html.haml
@@ -0,0 +1,17 @@
+- page_title _("To-Do List")
+
+= render_two_factor_auth_recovery_settings_check
+= render_dashboard_ultimate_trial(current_user)
+
+= render_if_exists 'shared/dashboard/saml_reauth_notice',
+  groups_requiring_saml_reauth: todo_groups_requiring_saml_reauth(@todos)
+
+- add_page_specific_style 'page_bundles/todos'
+- add_issuable_stylesheet
+- user_has_todos = current_user.todos.any?
+
+- if user_has_todos
+  = render ::Layouts::PageHeadingComponent.new(_('To-Do List'))
+  #js-todos-app-root
+- else
+  = render 'dashboard/todos/user_has_no_todos'
diff --git a/config/feature_flags/wip/todos_vue_application.yml b/config/feature_flags/wip/todos_vue_application.yml
new file mode 100644
index 000000000000..c06f58f74d68
--- /dev/null
+++ b/config/feature_flags/wip/todos_vue_application.yml
@@ -0,0 +1,9 @@
+---
+name: todos_vue_application
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/464069
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162587
+rollout_issue_url:
+milestone: '17.4'
+group: group::personal productivity
+type: wip
+default_enabled: false
diff --git a/config/routes/dashboard.rb b/config/routes/dashboard.rb
index a9b4582a1a4a..a78775f9afef 100644
--- a/config/routes/dashboard.rb
+++ b/config/routes/dashboard.rb
@@ -16,6 +16,7 @@
 
     resources :todos, only: [:index, :destroy] do
       collection do
+        get :vue
         delete :destroy_all
         patch :bulk_restore
       end
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
index b66ad8f1e3c2..9f5bd1a1a56b 100644
--- a/spec/controllers/dashboard/todos_controller_spec.rb
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Dashboard::TodosController do
+RSpec.describe Dashboard::TodosController, feature_category: :notifications do
   let_it_be(:user) { create(:user) }
   let_it_be(:project) { create(:project, developers: user) }
   let_it_be(:author) { create(:user) }
@@ -157,6 +157,32 @@
     end
   end
 
+  describe 'GET #vue' do
+    context 'with todos_vue_application on' do
+      before do
+        stub_feature_flags(todos_vue_application: true)
+      end
+
+      it 'renders 200' do
+        get :vue
+
+        expect(response).to have_gitlab_http_status(:ok)
+      end
+    end
+
+    context 'with todos_vue_application off' do
+      before do
+        stub_feature_flags(todos_vue_application: false)
+      end
+
+      it 'redirects to #index' do
+        get :vue
+
+        expect(response).to redirect_to dashboard_todos_path
+      end
+    end
+  end
+
   describe 'PATCH #restore' do
     let(:todo) { create(:todo, :done, user: user, project: project, author: author) }
 
-- 
GitLab